diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..b4d509648 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +# Ignore git objects +.git/ +.gitignore +.gitlab-ci.yml +.gitmodules + +# Ignore temperory volumes +deploy/compose/volumes + +# creating a docker image +.dockerignore + +# Ignore any virtual environment configuration files +.env* +.venv/ +env/ +# Ignore python bytecode files +*.pyc +__pycache__/ diff --git a/.gitignore b/.gitignore index 241cbc4f0..7094b42f7 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ docs/_* docs/notebooks docs/experimental docs/tools + +# Developing examples +RetrievalAugmentedGeneration/examples/simple_rag_api_catalog/ +deploy/compose/simple-rag-api-catalog.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 22aece8e7..4f67ebf67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,3 +9,17 @@ repos: args: - --license-filepath - RetrievalAugmentedGeneration/LICENSE.md +- repo: https://github.com/psf/black + rev: 19.10b0 + hooks: + - id: black + args: ["--skip-string-normalization", "--line-length=119"] + additional_dependencies: ['click==8.0.4'] +- repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + name: isort (python) + args: ["--multi-line=3", "--trailing-comma", "--force-grid-wrap=0", "--use-parenthese", "--line-width=119", "--ws"] + + diff --git a/CHANGELOG.md b/CHANGELOG.md index ad637060c..6112a8840 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,38 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.7.0] - 2024-06-18 + +This release switches all examples to use cloud hosted GPU accelerated LLM and embedding models from [Nvidia API Catalog](https://build.nvidia.com) as default. It also deprecates support to deploy on-prem models using NeMo Inference Framework Container and adds support to deploy accelerated generative AI models across the cloud, data center, and workstation using [latest Nvidia NIM-LLM](https://docs.nvidia.com/nim/large-language-models/latest/introduction.html). + +### Added +- Added model [auto download and caching support for `nemo-retriever-embedding-microservice` and `nemo-retriever-reranking-microservice`](./deploy/compose/docker-compose-nim-ms.yaml). Updated steps to deploy the services can be found [here](https://nvidia.github.io/GenerativeAIExamples/latest/nim-llms.html). +- [Multimodal RAG Example enhancements](https://nvidia.github.io/GenerativeAIExamples/latest/multimodal-data.html) + - Moved to the [PDF Plumber library](https://pypi.org/project/pdfplumber/) for parsing text and images. + - Added `pgvector` vector DB support. + - Added support to ingest files with .pptx extension + - Improved accuracy of image parsing by using [tesseract-ocr](https://pypi.org/project/tesseract-ocr/) +- Added a [new notebook showcasing RAG usecase using accelerated NIM based on-prem deployed models](./notebooks/08_RAG_Langchain_with_Local_NIM.ipynb) +- Added a [new experimental example](./experimental/rag-developer-chatbot/) showcasing how to create a developer-focused RAG chatbot using RAPIDS cuDF source code and API documentation. +- Added a [new experimental example](./experimental/event-driven-rag-cve-analysis/) demonstrating how NVIDIA Morpheus, NIMs, and RAG pipelines can be integrated to create LLM-based agent pipelines. + +### Changed +- All examples now use llama3 models from [Nvidia API Catalog](https://build.nvidia.com/search?term=llama3) as default. Summary of updated examples and the model it uses is available [here](https://nvidia.github.io/GenerativeAIExamples/latest/index.html#developer-rag-examples). +- Switched default embedding model of all examples to [Snowflake arctic-embed-I model](https://build.nvidia.com/snowflake/arctic-embed-l) +- Added more verbose logs and support to configure [log level for chain server using LOG_LEVEL enviroment variable](https://nvidia.github.io/GenerativeAIExamples/latest/configuration.html#chain-server). +- Bumped up version of `langchain-nvidia-ai-endpoints`, `sentence-transformers` package and `milvus` containers +- Updated base containers to use ubuntu 22.04 image `nvcr.io/nvidia/base/ubuntu:22.04_20240212` +- Added `llama-index-readers-file` as dependency to avoid runtime package installation within chain server. + + +### Deprecated +- Deprecated support of on-prem LLM model deployment using [NeMo Inference Framework Container](https://github.com/NVIDIA/GenerativeAIExamples/blob/v0.6.0/deploy/compose/rag-app-text-chatbot.yaml#L2). Developers can use [Nvidia NIM-LLM to deploy TensorRT optimized models on-prem and plug them in with existing examples](https://nvidia.github.io/GenerativeAIExamples/latest/nim-llms.html). +- Deprecated [kubernetes operator support](https://github.com/NVIDIA/GenerativeAIExamples/tree/v0.6.0/deploy/k8s-operator/kube-trailblazer). +- `nvolveqa_40k` embedding model was deprecated from [Nvidia API Catalog](https://build.nvidia.com). Updated all [notebooks](./notebooks/) and [experimental artifacts](./experimental/) to use [Nvidia embed-qa-4 model](https://build.nvidia.com/nvidia/embed-qa-4) instead. +- Removed [notebooks numbered 00-04](https://github.com/NVIDIA/GenerativeAIExamples/tree/v0.6.0/notebooks), which used on-prem LLM model deployment using deprecated [NeMo Inference Framework Container](https://github.com/NVIDIA/GenerativeAIExamples/blob/v0.6.0/deploy/compose/rag-app-text-chatbot.yaml#L2). + + ## [0.6.0] - 2024-05-07 ### Added diff --git a/README.md b/README.md index aebece7c9..70fc8dbdf 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ State-of-the-art Generative AI examples that are easy to deploy, test, and exten ## NVIDIA NGC -Generative AI Examples can use models and GPUs from the [NVIDIA NGC: AI Development Catalog](https://catalog.ngc.nvidia.com). +Generative AI Examples can use models and GPUs from the [NVIDIA API Catalog](https://catalog.ngc.nvidia.com). Sign up for a [free NGC developer account](https://ngc.nvidia.com/signin) to access: @@ -27,20 +27,18 @@ The examples demonstrate how to combine NVIDIA GPU acceleration with popular LLM The examples are easy to deploy with [Docker Compose](https://docs.docker.com/compose/). Examples support local and remote inference endpoints. -If you have a GPU, you can inference locally with [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM). +If you have a GPU, you can inference locally with an [NVIDIA NIM for LLMs](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/nim/containers/nim_llm). If you don't have a GPU, you can inference and embed remotely with [NVIDIA API Catalog endpoints](https://build.nvidia.com/explore/discover). | Model | Embedding | Framework | Description | Multi-GPU | TRT-LLM | NVIDIA Endpoints | Triton | Vector Database | | ---------------------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ------- | ---------------- | ------ | ------------------ | -| mixtral_8x7b | ai-embed-qa-4 | LangChain | NVIDIA API Catalog endpoints chat bot [[code](./RetrievalAugmentedGeneration/examples/nvidia_api_catalog/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/api-catalog.html)] | No | No | Yes | Yes | Milvus or pgvector | -| llama-2 | UAE-Large-V1 | LlamaIndex | Canonical QA Chatbot [[code](./RetrievalAugmentedGeneration/examples/developer_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/local-gpu.html)] | [Yes](https://nvidia.github.io/GenerativeAIExamples/latest/multi-gpu.html) | Yes | No | Yes | Milvus or pgvector | -| llama-2 | all-MiniLM-L6-v2 | LlamaIndex | Chat bot, GeForce, Windows [[repo](https://github.com/NVIDIA/trt-llm-rag-windows/tree/release/1.0)] | No | Yes | No | No | FAISS | -| llama-2 | ai-embed-qa-4 | LangChain | Chat bot with query decomposition agent [[code](./RetrievalAugmentedGeneration/examples/query_decomposition_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/query-decomposition.html)] | No | No | Yes | Yes | Milvus or pgvector | -| mixtral_8x7b | ai-embed-qa-4 | LangChain | Minimilastic example: RAG with NVIDIA AI Foundation Models [[code](./examples/5_mins_rag_no_gpu/), [README](./examples/README.md#rag-in-5-minutes-example)] | No | No | Yes | Yes | FAISS | -| mixtral_8x7b
Deplot
Neva-22b | ai-embed-qa-4 | Custom | Chat bot with multimodal data [[code](./RetrievalAugmentedGeneration/examples/multimodal_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/multimodal-data.html)] | No | No | Yes | No | Milvus or pvgector | -| llama-2 | UAE-Large-V1 | LlamaIndex | Chat bot with quantized LLM model [[docs](https://nvidia.github.io/GenerativeAIExamples/latest/quantized-llm-model.html)] | Yes | Yes | No | Yes | Milvus or pgvector | +| llama3-70b | snowflake-arctic-embed-l | LangChain | NVIDIA API Catalog endpoints chat bot [[code](./RetrievalAugmentedGeneration/examples/nvidia_api_catalog/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/api-catalog.html)] | No | No | Yes | Yes | Milvus or pgvector | +| llama3-8b | snowflake-arctic-embed-l | LlamaIndex | Canonical QA Chatbot [[code](./RetrievalAugmentedGeneration/examples/developer_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/api-catalog.html#using-the-llamaindex-data-framework)] | [Yes](https://nvidia.github.io/GenerativeAIExamples/latest/multi-gpu.html) | Yes | No | Yes | Milvus or pgvector | +| llama3-70b | snowflake-arctic-embed-l | LangChain | Chat bot with query decomposition agent [[code](./RetrievalAugmentedGeneration/examples/query_decomposition_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/query-decomposition.html)] | No | No | Yes | Yes | Milvus or pgvector | +| llama3-70b | ai-embed-qa-4 | LangChain | Minimilastic example: RAG with NVIDIA AI Foundation Models [[code](./examples/5_mins_rag_no_gpu/), [README](./examples/README.md#rag-in-5-minutes-example)] | No | No | Yes | Yes | FAISS | +| llama3-8b
Deplot
Neva-22b | snowflake-arctic-embed-l | Custom | Chat bot with multimodal data [[code](./RetrievalAugmentedGeneration/examples/multimodal_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/multimodal-data.html)] | No | No | Yes | No | Milvus or pvgector | | llama3-70b | none | PandasAI | Chat bot with structured data [[code](./RetrievalAugmentedGeneration/examples/structured_data_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/structured-data.html)] | No | No | Yes | No | none | -| llama-2 | ai-embed-qa-4 | LangChain | Chat bot with multi-turn conversation [[code](./RetrievalAugmentedGeneration/examples/multi_turn_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/multi-turn.html)] | No | No | Yes | No | Milvus or pgvector | +| llama3-8b | snowflake-arctic-embed-l | LangChain | Chat bot with multi-turn conversation [[code](./RetrievalAugmentedGeneration/examples/multi_turn_rag/), [docs](https://nvidia.github.io/GenerativeAIExamples/latest/multi-turn.html)] | No | No | Yes | No | Milvus or pgvector | ### Enterprise RAG Examples @@ -48,13 +46,13 @@ The enterprise RAG examples run as microservices distributed across multiple VMs These examples show how to orchestrate RAG pipelines with [Kubernetes](https://kubernetes.io/) and deployed with [Helm](https://helm.sh/). Enterprise RAG examples include a [Kubernetes operator](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) for LLM lifecycle management. -It is compatible with the [NVIDIA GPU operator](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/gpu-operator) that automates GPU discovery and lifecycle management in a Kubernetes cluster. +It is compatible with the [NVIDIA GPU Operator](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/gpu-operator) that automates GPU discovery and lifecycle management in a Kubernetes cluster. Enterprise RAG examples also support local and remote inference with [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM) and [NVIDIA API Catalog endpoints](https://build.nvidia.com/explore/discover). | Model | Embedding | Framework | Description | Multi-GPU | Multi-node | TRT-LLM | NVIDIA Endpoints | Triton | Vector Database | | ------- | ----------- | ---------- | -------------------------------------------------------------------------- | --------- | ---------- | ------- | ---------------- | ------ | --------------- | -| llama-2 | NV-Embed-QA | LlamaIndex | Chat bot, Kubernetes deployment [[README](./docs/developer-llm-operator/)] | No | No | Yes | No | Yes | Milvus | +| llama-3 | nv-embed-qa-4 | LlamaIndex | Chat bot, Kubernetes deployment [[chart](https://registry.ngc.nvidia.com/orgs/ohlfw0olaadg/teams/ea-participants/helm-charts/rag-app-text-chatbot)] | No | No | Yes | No | Yes | Milvus | ### Generative AI Model Examples @@ -89,6 +87,16 @@ These are open source connectors for NVIDIA-hosted and self-hosted API endpoints |[NVIDIA Triton Inference Server](https://docs.llamaindex.ai/en/stable/examples/llm/nvidia_triton.html) | [LlamaIndex](https://www.llamaindex.ai/) |Yes|Yes|No|Triton inference server provides API access to hosted LLM models over gRPC. | |[NVIDIA TensorRT-LLM](https://docs.llamaindex.ai/en/stable/examples/llm/nvidia_tensorrt.html) | [LlamaIndex](https://www.llamaindex.ai/) |Yes|Yes|No|TensorRT-LLM provides a Python API to build TensorRT engines with state-of-the-art optimizations for LLM inference on NVIDIA GPUs. | + +## Related NVIDIA RAG Projects + +- [NVIDIA Tokkio LLM-RAG](https://docs.nvidia.com/ace/latest/workflows/tokkio/text/Tokkio_LLM_RAG_Bot.html): Use Tokkio to add avatar animation for RAG responses. + +- [RAG on Windows using TensorRT-LLM and LlamaIndex](https://github.com/NVIDIA/ChatRTX): Create RAG chatbots on Windows using TensorRT-LLM. + +- [Hybrid RAG Project on AI Workbench](https://github.com/NVIDIA/workbench-example-hybrid-rag): Run an NVIDIA AI Workbench example project for RAG. + + ## Support, Feedback, and Contributing We're posting these examples on GitHub to support the NVIDIA LLM community and facilitate feedback. diff --git a/RetrievalAugmentedGeneration/Dockerfile b/RetrievalAugmentedGeneration/Dockerfile index 463b8cb5f..cb504a084 100644 --- a/RetrievalAugmentedGeneration/Dockerfile +++ b/RetrievalAugmentedGeneration/Dockerfile @@ -1,5 +1,5 @@ ARG BASE_IMAGE_URL=nvcr.io/nvidia/base/ubuntu -ARG BASE_IMAGE_TAG=20.04_x64_2022-09-23 +ARG BASE_IMAGE_TAG=22.04_20240212 FROM ${BASE_IMAGE_URL}:${BASE_IMAGE_TAG} @@ -11,7 +11,7 @@ RUN apt update && \ apt install -y curl software-properties-common libgl1 libglib2.0-0 && \ add-apt-repository ppa:deadsnakes/ppa && \ apt update && apt install -y python3.10 python3.10-dev python3.10-distutils && \ - apt-get clean + apt-get clean # Install pip for python3.10 RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10 @@ -24,7 +24,7 @@ RUN apt autoremove -y curl software-properties-common # Install common dependencies for all examples RUN --mount=type=bind,source=RetrievalAugmentedGeneration/requirements.txt,target=/opt/requirements.txt \ pip3 install --no-cache-dir -r /opt/requirements.txt - + # Install any example specific dependency if available ARG EXAMPLE_NAME COPY RetrievalAugmentedGeneration/examples/${EXAMPLE_NAME} /opt/RetrievalAugmentedGeneration/example @@ -32,12 +32,24 @@ RUN if [ -f "/opt/RetrievalAugmentedGeneration/example/requirements.txt" ] ; the pip3 install --no-cache-dir -r /opt/RetrievalAugmentedGeneration/example/requirements.txt ; else \ echo "Skipping example dependency installation, since requirements.txt was not found" ; \ fi +RUN python3.10 -m nltk.downloader averaged_perceptron_tagger +RUN if [ "${EXAMPLE_NAME}" = "multimodal_rag" ] ; then \ + apt update && \ + apt install -y libreoffice && \ + apt install -y tesseract-ocr ; \ + fi # Copy required common modules for all examples COPY RetrievalAugmentedGeneration/__init__.py /opt/RetrievalAugmentedGeneration/ COPY RetrievalAugmentedGeneration/common /opt/RetrievalAugmentedGeneration/common COPY integrations /opt/integrations COPY tools /opt/tools +RUN mkdir /tmp-data/; mkdir /tmp-data/nltk_data/ +RUN chmod 777 -R /tmp-data +RUN chown 1000:1000 -R /tmp-data +ENV NLTK_DATA=/tmp-data/nltk_data/ +ENV HF_HOME=/tmp-data + WORKDIR /opt ENTRYPOINT ["uvicorn", "RetrievalAugmentedGeneration.common.server:app"] diff --git a/RetrievalAugmentedGeneration/common/configuration.py b/RetrievalAugmentedGeneration/common/configuration.py index 7a6656f31..da3a7967e 100644 --- a/RetrievalAugmentedGeneration/common/configuration.py +++ b/RetrievalAugmentedGeneration/common/configuration.py @@ -67,8 +67,8 @@ class LLMConfig(ConfigWizard): ) model_engine: str = configfield( "model_engine", - default="triton-trt-llm", - help_txt="The server type of the hosted model. Allowed values are triton-trt-llm and nemo-infer", + default="nvidia-ai-endpoints", + help_txt="The server type of the hosted model. Allowed values are nvidia-ai-endpoints", ) model_name_pandas_ai: str = configfield( "model_name_pandas_ai", @@ -86,7 +86,7 @@ class TextSplitterConfig(ConfigWizard): model_name: str = configfield( "model_name", - default="WhereIsAI/UAE-Large-V1", + default="Snowflake/snowflake-arctic-embed-l", help_txt="The name of Sentence Transformer model used for SentenceTransformer TextSplitter.", ) chunk_size: int = configfield( @@ -110,12 +110,12 @@ class EmbeddingConfig(ConfigWizard): model_name: str = configfield( "model_name", - default="WhereIsAI/UAE-Large-V1", + default="snowflake/arctic-embed-l", help_txt="The name of huggingface embedding model.", ) model_engine: str = configfield( "model_engine", - default="huggingface", + default="nvidia-ai-endpoints", help_txt="The server type of the hosted model. Allowed values are hugginface", ) dimensions: int = configfield( @@ -148,6 +148,16 @@ class RetrieverConfig(ConfigWizard): default=0.25, help_txt="The minimum confidence score for the retrieved values to be considered", ) + nr_url: str = configfield( + "nr_url", + default='http://retrieval-ms:8000', + help_txt="The nemo retriever microservice url", + ) + nr_pipeline: str = configfield( + "nr_pipeline", + default='ranked_hybrid', + help_txt="The name of the nemo retriever pipeline one of ranked_hybrid or hybrid", + ) @configclass @@ -162,12 +172,9 @@ class PromptsConfig(ConfigWizard): chat_template: str = configfield( "chat_template", default=( - "[INST] <>" "You are a helpful, respectful and honest assistant." "Always answer as helpfully as possible, while being safe." "Please ensure that your responses are positive in nature." - "<>" - "[/INST] {context_str} [INST] {query_str} [/INST]" ), help_txt="Prompt template for chat.", ) diff --git a/RetrievalAugmentedGeneration/common/server.py b/RetrievalAugmentedGeneration/common/server.py index 569cb9fe8..ca3acf56d 100644 --- a/RetrievalAugmentedGeneration/common/server.py +++ b/RetrievalAugmentedGeneration/common/server.py @@ -37,7 +37,7 @@ from pymilvus.exceptions import MilvusException, MilvusUnavailableException from RetrievalAugmentedGeneration.common.tracing import llamaindex_instrumentation_wrapper -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=os.environ.get('LOGLEVEL', 'INFO').upper()) logger = logging.getLogger(__name__) # create the FastAPI server @@ -193,7 +193,7 @@ async def request_validation_exception_handler( def health_check(): """ Perform a Health Check - + Returns 200 when service is up. This does not check the health of downstream services. """ @@ -218,7 +218,7 @@ async def upload_document(request: Request, file: UploadFile = File(...)) -> JSO return JSONResponse(content={"message": "No files provided"}, status_code=200) try: - upload_folder = "uploaded_files" + upload_folder = "/tmp-data/uploaded_files" upload_file = os.path.basename(file.filename) if not upload_file: raise RuntimeError("Error parsing uploaded filename.") @@ -285,6 +285,7 @@ async def generate_answer(request: Request, prompt: Prompt) -> StreamingResponse def response_generator(): resp_id = str(uuid4()) if generator: + logger.debug(f"Generated response chunks\n") for chunk in generator: chain_response = ChainResponse() response_choice = ChainResponseChoices( @@ -296,11 +297,13 @@ def response_generator(): ) chain_response.id = resp_id chain_response.choices.append(response_choice) + logger.debug(response_choice) yield "data: " + str(chain_response.json()) + "\n\n" chain_response = ChainResponse() response_choice = ChainResponseChoices(finish_reason="[DONE]") chain_response.id = resp_id chain_response.choices.append(response_choice) + logger.debug(response_choice) yield "data: " + str(chain_response.json()) + "\n\n" else: chain_response = ChainResponse() @@ -412,7 +415,9 @@ async def delete_document(request: Request, filename: str) -> JSONResponse: try: example = app.example() if hasattr(example, "delete_documents") and callable(example.delete_documents): - example.delete_documents([filename]) + status = example.delete_documents([filename]) + if not status: + raise Exception(f"Error in deleting document {filename}") return JSONResponse(content={"message": f"Document {filename} deleted successfully"}, status_code=200) raise NotImplementedError("Example class has not implemented the delete_document method.") diff --git a/RetrievalAugmentedGeneration/common/tracing.py b/RetrievalAugmentedGeneration/common/tracing.py index 81f40627d..4e24337d4 100644 --- a/RetrievalAugmentedGeneration/common/tracing.py +++ b/RetrievalAugmentedGeneration/common/tracing.py @@ -17,8 +17,8 @@ import os import llama_index -from llama_index.core.callbacks.base import CallbackManager -from langchain.callbacks.base import BaseCallbackHandler +from langchain.callbacks.base import BaseCallbackHandler as langchain_base_cb_handler +from llama_index.core.callbacks.simple_llm_handler import SimpleLLMHandler as llama_index_base_cb_handler from opentelemetry import trace, context from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import TracerProvider @@ -40,19 +40,22 @@ trace.set_tracer_provider(provider) tracer = trace.get_tracer("chain-server") + if os.environ.get("ENABLE_TRACING") == "true": # Configure Propagator used for processing trace context received by the Chain Server propagator = TraceContextTextMapPropagator() - # Configure Langchain OpenTelemetry callback handler + # Configure Langchain OpenTelemetry callback handler langchain_cb_handler = langchain_otel_cb.OpenTelemetryCallbackHandler(tracer) - + # Configure LlamaIndex OpenTelemetry callback handler - llama_index.global_handler = llama_index_otel_cb.OpenTelemetryCallbackHandler(tracer) + llama_index_cb_handler = llama_index_otel_cb.OpenTelemetryCallbackHandler(tracer) + else: propagator = CompositePropagator([]) # No-op propagator - langchain_cb_handler = BaseCallbackHandler() - + langchain_cb_handler = langchain_base_cb_handler() + llama_index_cb_handler = llama_index_base_cb_handler() + set_global_textmap(propagator) # Wrapper Function to perform LlamaIndex instrumentation diff --git a/RetrievalAugmentedGeneration/common/utils.py b/RetrievalAugmentedGeneration/common/utils.py index c880d9dc9..e98d9e2c1 100644 --- a/RetrievalAugmentedGeneration/common/utils.py +++ b/RetrievalAugmentedGeneration/common/utils.py @@ -52,13 +52,15 @@ from llama_index.core.indices.base_retriever import BaseRetriever from llama_index.core.indices.query.schema import QueryBundle from llama_index.core.schema import NodeWithScore + from RetrievalAugmentedGeneration.common.tracing import llama_index_cb_handler + from llama_index.core.callbacks import CallbackManager except Exception as e: logger.error(f"Llamaindex import failed with error: {e}") try: from langchain.text_splitter import SentenceTransformersTokenTextSplitter - from langchain.embeddings import HuggingFaceEmbeddings - from langchain.vectorstores import FAISS + from langchain_community.embeddings import HuggingFaceEmbeddings + from langchain_community.vectorstores import FAISS except Exception as e: logger.error(f"Langchain import failed with error: {e}") @@ -87,8 +89,6 @@ from langchain_core.embeddings import Embeddings from langchain_core.language_models.chat_models import SimpleChatModel from langchain.llms.base import LLM -from integrations.langchain.llms.triton_trt_llm import TensorRTLLM -from integrations.langchain.embeddings.nemo_embed import NemoEmbeddings from RetrievalAugmentedGeneration.common import configuration if TYPE_CHECKING: @@ -138,7 +138,8 @@ def set_service_context(**kwargs) -> None: llm = LangChainLLM(get_llm(**kwargs)) embedding = LangchainEmbedding(get_embedding_model()) service_context = ServiceContext.from_defaults( - llm=llm, embed_model=embedding + llm=llm, embed_model=embedding, + callback_manager=CallbackManager([llama_index_cb_handler]) ) set_global_service_context(service_context) @@ -266,29 +267,17 @@ def get_llm(**kwargs) -> LLM | SimpleChatModel: settings = get_config() logger.info(f"Using {settings.llm.model_engine} as model engine for llm. Model name: {settings.llm.model_name}") - if settings.llm.model_engine == "triton-trt-llm": - trtllm = TensorRTLLM( # type: ignore - server_url=settings.llm.server_url, - model_name=settings.llm.model_name, - temperature = kwargs.get('temperature', None), - top_p = kwargs.get('top_p', None), - tokens = kwargs.get('max_tokens', None) - ) - unused_params = [key for key in kwargs.keys() if key not in ['temperature', 'top_p', 'max_tokens', 'stream']] - if unused_params: - logger.warning(f"The following parameters from kwargs are not supported: {unused_params} for {settings.llm.model_engine}") - return trtllm - elif settings.llm.model_engine == "nvidia-ai-endpoints": + if settings.llm.model_engine == "nvidia-ai-endpoints": unused_params = [key for key in kwargs.keys() if key not in ['temperature', 'top_p', 'max_tokens']] if unused_params: logger.warning(f"The following parameters from kwargs are not supported: {unused_params} for {settings.llm.model_engine}") if settings.llm.server_url: logger.info(f"Using llm model {settings.llm.model_name} hosted at {settings.llm.server_url}") - return ChatNVIDIA(model=settings.llm.model_name, + return ChatNVIDIA(base_url=f"http://{settings.llm.server_url}/v1", + model=settings.llm.model_name, temperature = kwargs.get('temperature', None), top_p = kwargs.get('top_p', None), - max_tokens = kwargs.get('max_tokens', None) - ).mode("nim", base_url=f"http://{settings.llm.server_url}/v1") + max_tokens = kwargs.get('max_tokens', None)) else: logger.info(f"Using llm model {settings.llm.model_name} from api catalog") return ChatNVIDIA(model=settings.llm.model_name, @@ -296,7 +285,7 @@ def get_llm(**kwargs) -> LLM | SimpleChatModel: top_p = kwargs.get('top_p', None), max_tokens = kwargs.get('max_tokens', None)) else: - raise RuntimeError("Unable to find any supported Large Language Model server. Supported engines are triton-trt-llm, nvidia-ai-endpoints.") + raise RuntimeError("Unable to find any supported Large Language Model server. Supported engine name is nvidia-ai-endpoints.") @lru_cache @@ -321,18 +310,12 @@ def get_embedding_model() -> Embeddings: elif settings.embeddings.model_engine == "nvidia-ai-endpoints": if settings.embeddings.server_url: logger.info(f"Using embedding model {settings.embeddings.model_name} hosted at {settings.embeddings.server_url}") - return NVIDIAEmbeddings(model=settings.embeddings.model_name).mode("nim", base_url=f"http://{settings.embeddings.server_url}/v1") + return NVIDIAEmbeddings(base_url=f"http://{settings.embeddings.server_url}/v1", model=settings.embeddings.model_name, truncate="END") else: logger.info(f"Using embedding model {settings.embeddings.model_name} hosted at api catalog") - return NVIDIAEmbeddings(model=settings.embeddings.model_name) - elif settings.embeddings.model_engine == "nemo-embed": - nemo_embed = NemoEmbeddings( - server_url=f"http://{settings.embeddings.server_url}/v1/embeddings", - model_name=settings.embeddings.model_name, - ) - return nemo_embed + return NVIDIAEmbeddings(model=settings.embeddings.model_name, truncate="END") else: - raise RuntimeError("Unable to find any supported embedding model. Supported engine is huggingface.") + raise RuntimeError("Unable to find any supported embedding model. Supported engine is huggingface and nvidia-ai-endpoints.") def get_text_splitter() -> SentenceTransformersTokenTextSplitter: @@ -376,7 +359,7 @@ def get_docs_vectorstore_langchain(vectorstore: VectorStore) -> List[str]: logger.error(f"Error occurred while retrieving documents: {e}") return [] -def del_docs_vectorstore_langchain(vectorstore: VectorStore, filenames: List[str]): +def del_docs_vectorstore_langchain(vectorstore: VectorStore, filenames: List[str]) -> bool: """Delete documents from the vector index implemented in LangChain.""" settings = get_config() @@ -387,13 +370,21 @@ def del_docs_vectorstore_langchain(vectorstore: VectorStore, filenames: List[str in_memory_docstore = vectorstore.docstore._dict for filename in filenames: ids_list = [doc_id for doc_id, doc_data in in_memory_docstore.items() if extract_filename(doc_data.metadata) == filename] + if not len(ids_list): + logger.info("File does not exist in the vectorstore") + return False vectorstore.delete(ids_list) logger.info(f"Deleted documents with filenames {filename}") elif settings.vector_store.name == "pgvector": with vectorstore._make_session() as session: - embedding_doc_store = session.query(vectorstore.EmbeddingStore.custom_id, vectorstore.EmbeddingStore.document, vectorstore.EmbeddingStore.cmetadata).all() + collection = vectorstore.get_collection(session) + filter_by = vectorstore.EmbeddingStore.collection_id == collection.uuid + embedding_doc_store = session.query(vectorstore.EmbeddingStore.custom_id, vectorstore.EmbeddingStore.document, vectorstore.EmbeddingStore.cmetadata).filter(filter_by).all() for filename in filenames: ids_list = [doc_id for doc_id, doc_data, metadata in embedding_doc_store if extract_filename(metadata) == filename] + if not len(ids_list): + logger.info("File does not exist in the vectorstore") + return False vectorstore.delete(ids_list) logger.info(f"Deleted documents with filenames {filename}") elif settings.vector_store.name == "milvus": @@ -401,10 +392,15 @@ def del_docs_vectorstore_langchain(vectorstore: VectorStore, filenames: List[str milvus_data = vectorstore.col.query(expr="pk >= 0", output_fields=["pk","source", "text"]) for filename in filenames: ids_list = [metadata["pk"] for metadata in milvus_data if extract_filename(metadata) == filename] + if not len(ids_list): + logger.info("File does not exist in the vectorstore") + return False vectorstore.col.delete(f"pk in {ids_list}") logger.info(f"Deleted documents with filenames {filename}") + return True except Exception as e: logger.error(f"Error occurred while deleting documents: {e}") + return False def get_docs_vectorstore_llamaindex() -> List[str]: @@ -440,7 +436,7 @@ def get_docs_vectorstore_llamaindex() -> List[str]: return [] -def del_docs_vectorstore_llamaindex(filenames: List[str]): +def del_docs_vectorstore_llamaindex(filenames: List[str]) -> bool: """Delete documents from the vector index implemented in LlamaIndex.""" settings = get_config() @@ -460,10 +456,13 @@ def del_docs_vectorstore_llamaindex(filenames: List[str]): query_res = client.query(collection_name=collection_name, filter=f"filename == '{filename}'", output_fields=["id"]) if not query_res: - return + logger.info("File does not exist in the vectorstore") + return False ids = [entry.get('id') for entry in query_res] res = client.delete(collection_name=collection_name, filter=f"id in {str(ids)}") logger.info(f"Deleted documents with filenames {filename}") + return True except Exception as e: logger.error(f"Error occurred while deleting documents: {e}") + return False diff --git a/RetrievalAugmentedGeneration/examples/developer_rag/chains.py b/RetrievalAugmentedGeneration/examples/developer_rag/chains.py index 5c9c5ebb0..65b4c6c27 100644 --- a/RetrievalAugmentedGeneration/examples/developer_rag/chains.py +++ b/RetrievalAugmentedGeneration/examples/developer_rag/chains.py @@ -27,6 +27,9 @@ from llama_index.core.node_parser import LangchainNodeParser from llama_index.llms.langchain import LangChainLLM from llama_index.embeddings.langchain import LangchainEmbedding +from RetrievalAugmentedGeneration.common.tracing import llama_index_cb_handler +from llama_index.core import Settings +from llama_index.core.callbacks import CallbackManager from langchain_core.output_parsers.string import StrOutputParser from langchain_core.prompts.chat import ChatPromptTemplate @@ -49,7 +52,7 @@ ) # nltk downloader -nltk.download("averaged_perceptron_tagger") +# nltk.download("averaged_perceptron_tagger") # prestage the embedding model _ = get_embedding_model() @@ -66,6 +69,7 @@ class QAChatbot(BaseExample): def ingest_docs(self, filepath: str, filename: str): """Ingest documents to the VectorDB.""" try: + Settings.callback_manager = CallbackManager([llama_index_cb_handler]) logger.info(f"Ingesting {filename} in vectorDB") _, ext = os.path.splitext(filename) @@ -116,36 +120,23 @@ def llm_chain( logger.info("Using llm to generate response directly without knowledge base.") set_service_context(**kwargs) # TODO Include chat_history - prompt = get_config().prompts.chat_template.format( - context_str="", query_str=query - ) + prompt = get_config().prompts.chat_template logger.info(f"Prompt used for response generation: {prompt}") - # stream_complete is returning empty response with NIM - # TODO: Use llama_index llm wrapper to stream response - if get_config().llm.model_engine == "triton-trt-llm": - llm = LangChainLLM(get_llm(**kwargs)) - response = llm.stream_complete( - prompt, - tokens=kwargs.get("max_tokens", None), - callbacks=[self.cb_handler], - ) - gen_response = (resp.delta for resp in response) - return gen_response - else: - # This is for get_config().llm.model_engine == "nvidia-ai-endpoints-nim" - user_input = [("user", get_config().prompts.chat_template)] + system_message = [("system", prompt)] + user_input = [("user", "{query_str}")] - prompt_template = ChatPromptTemplate.from_messages(user_input) + prompt_template = ChatPromptTemplate.from_messages( + system_message + user_input + ) - llm = get_llm(**kwargs) + llm = get_llm(**kwargs) - chain = prompt_template | llm | StrOutputParser() - augmented_user_input = "\n\nQuestion: " + query + "\n" - return chain.stream( - {"context_str": "", "query_str": query}, - config={"callbacks": [self.cb_handler]}, - ) + chain = prompt_template | llm | StrOutputParser() + return chain.stream( + {"query_str": query}, + config={"callbacks": [self.cb_handler]}, + ) def rag_chain( self, query: str, chat_history: List["Message"], **kwargs @@ -159,7 +150,7 @@ def rag_chain( retriever = get_doc_retriever(num_nodes=get_config().retriever.top_k) qa_template = Prompt(get_config().prompts.rag_template) - logger.info(f"Prompt used for response generation: {qa_template}") + logger.info(f"Prompt template used for response generation: {qa_template}") # Handling Retrieval failure nodes = retriever.retrieve(query) diff --git a/RetrievalAugmentedGeneration/examples/multi_turn_rag/chains.py b/RetrievalAugmentedGeneration/examples/multi_turn_rag/chains.py index 3024d0acc..6dd8ad5fe 100644 --- a/RetrievalAugmentedGeneration/examples/multi_turn_rag/chains.py +++ b/RetrievalAugmentedGeneration/examples/multi_turn_rag/chains.py @@ -42,7 +42,6 @@ from RetrievalAugmentedGeneration.common.tracing import langchain_instrumentation_class_wrapper from operator import itemgetter -DOCS_DIR = os.path.abspath("./uploaded_files") document_embedder = get_embedding_model() text_splitter = None settings = get_config() @@ -74,8 +73,7 @@ def ingest_docs(self, filepath: str, filename: str): raise ValueError(f"{filename} is not a valid Text, PDF or Markdown file") try: # Load raw documents from the directory - # Data is copied to `DOCS_DIR` in common.server:upload_document - _path = os.path.join(DOCS_DIR, filename) + _path = filepath raw_documents = UnstructuredFileLoader(_path).load() if raw_documents: @@ -103,23 +101,25 @@ def llm_chain( # WAR: Disable chat history (UI consistency). chat_history = [] conversation_history = [(msg.role, msg.content) for msg in chat_history] - user_message = [("user", settings.prompts.chat_template)] + system_message = [("system", settings.prompts.chat_template)] + user_message = [("user", "{query_str}")] # TODO: Enable this block once conversation history is enabled for llm chain # Checking if conversation_history is not None and not empty # prompt_template = ChatPromptTemplate.from_messages( - # conversation_history + user_message + # system_message + conversation_history + user_message # ) if conversation_history else ChatPromptTemplate.from_messages( - # user_message + # system_message + user_message # ) prompt_template = ChatPromptTemplate.from_messages( - user_message + system_message + user_message ) llm = get_llm(**kwargs) chain = prompt_template | llm | StrOutputParser() - return chain.stream({"context_str": "", "query_str": query}, config={"callbacks":[self.cb_handler]}) + logger.info(f"Prompt used for response generation: {prompt_template.format(query_str=query)}") + return chain.stream({"query_str": query}, config={"callbacks":[self.cb_handler]}) def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Generator[str, None, None]: """Execute a Retrieval Augmented Generation chain using the components defined above.""" @@ -132,7 +132,7 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene # ("user", "{input}"), # ] # ) - + # This is a workaround Prompt Template chat_prompt = ChatPromptTemplate.from_messages( [ @@ -171,7 +171,9 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene if not docs: logger.warning("Retrieval failed to get any relevant context") return iter(["No response generated from LLM, make sure your query is relavent to the ingested document."]) - + + logger.debug(f"Retrieved docs are: {docs}") + chain = retrieval_chain | stream_chain for chunk in chain.stream({"input": query}, config={"callbacks":[self.cb_handler]}): @@ -204,6 +206,7 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene logger.warning("Retrieval failed to get any relevant context") return iter(["No response generated from LLM, make sure your query is relavent to the ingested document."]) + logger.debug(f"Retrieved documents are: {docs}") chain = retrieval_chain | stream_chain for chunk in chain.stream({"input": query}, config={"callbacks":[self.cb_handler]}): yield chunk diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/chains.py b/RetrievalAugmentedGeneration/examples/multimodal_rag/chains.py index fbadbf690..bcd686989 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/chains.py +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/chains.py @@ -18,6 +18,7 @@ from typing import Generator, List, Dict, Any from functools import lru_cache from traceback import print_exc +from langchain_community.document_loaders import UnstructuredFileLoader from RetrievalAugmentedGeneration.common.utils import utils_cache @@ -25,34 +26,29 @@ from RetrievalAugmentedGeneration.common.base import BaseExample from RetrievalAugmentedGeneration.example.llm.llm_client import LLMClient -from RetrievalAugmentedGeneration.example.retriever.embedder import NVIDIAEmbedders -from RetrievalAugmentedGeneration.example.retriever.vector import MilvusVectorClient -from RetrievalAugmentedGeneration.example.retriever.retriever import Retriever from RetrievalAugmentedGeneration.example.vectorstore.vectorstore_updater import update_vectorstore -from RetrievalAugmentedGeneration.common.utils import get_config +from RetrievalAugmentedGeneration.common.utils import ( + get_config, + create_vectorstore_langchain, + get_embedding_model, + get_text_splitter, + get_docs_vectorstore_langchain, + del_docs_vectorstore_langchain, + get_vectorstore +) from RetrievalAugmentedGeneration.common.tracing import langchain_instrumentation_class_wrapper +document_embedder = get_embedding_model() +text_splitter = None settings = get_config() sources = [] RESPONSE_PARAPHRASING_MODEL = settings.llm.model_name -@lru_cache -def get_vector_index(embed_dim: int = 1024) -> MilvusVectorClient: - return MilvusVectorClient(hostname="milvus", port="19530", collection_name=os.getenv('COLLECTION_NAME', "vector_db"), embedding_size=embed_dim) - -@lru_cache -def get_embedder(type: str = "query") -> NVIDIAEmbedders: - if type == "query": - embedder = NVIDIAEmbedders(name=settings.embeddings.model_name, type="query") - else: - embedder = NVIDIAEmbedders(name=settings.embeddings.model_name, type="passage") - return embedder - -@lru_cache -def get_doc_retriever(type: str = "query") -> Retriever: - embedder = get_embedder(type) - embedding_size = embedder.get_embedding_size() - return Retriever(embedder=get_embedder(type) , vector_client=get_vector_index(embedding_size)) +try: + docstore = create_vectorstore_langchain(document_embedder=document_embedder) +except Exception as e: + docstore = None + logger.info(f"Unable to connect to vector store during initialization: {e}") @utils_cache @lru_cache() @@ -66,17 +62,18 @@ class MultimodalRAG(BaseExample): def ingest_docs(self, filepath: str, filename: str): """Ingest documents to the VectorDB.""" - if not filename.endswith(".pdf"): - raise ValueError(f"{filename} is not a valid PDF file. Only PDF files are supported for multimodal rag. The PDF files can contain multimodal data.") + if not filename.endswith((".pdf",".pptx")): + raise ValueError(f"{filename} is not a valid PDF/PPTX file. Only PDF/PPTX files are supported for multimodal rag. The PDF/PPTX files can contain multimodal data.") try: - embedder = get_embedder(type="passage") - embedding_size = embedder.get_embedding_size() - update_vectorstore(os.path.abspath(filepath), get_vector_index(embedding_size), embedder, os.getenv('COLLECTION_NAME', "vector_db")) + _path = filepath + ds = get_vectorstore(docstore, document_embedder) + update_vectorstore(_path,ds,document_embedder,os.getenv('COLLECTION_NAME', "vector_db")) except Exception as e: logger.error(f"Failed to ingest document due to exception {e}") - print_exc() - raise ValueError("Failed to upload document. Please check chain server logs for details.") + raise ValueError( + "Failed to upload document. Please upload an unstructured text document." + ) def llm_chain( @@ -95,18 +92,35 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene logger.info("Using rag to generate response from document") # TODO integrate chat_history try: - retriever = get_doc_retriever(type="query") - context, sources = retriever.get_relevant_docs(query, limit=settings.retriever.top_k) - if not context: - logger.warning("Retrieval failed to get any relevant context") - return iter(["No response generated from LLM, make sure your query is relavent to the ingested document."]) - - augmented_prompt = "Relevant documents:" + context + "\n\n[[QUESTION]]\n\n" + query - system_prompt = settings.prompts.rag_template - logger.info(f"Formulated prompt for RAG chain: {system_prompt}\n{augmented_prompt}") - response = get_llm(model_name=RESPONSE_PARAPHRASING_MODEL, cb_handler=self.cb_handler, is_response_generator=True, **kwargs).chat_with_prompt(settings.prompts.rag_template, augmented_prompt) - return response - + ds = get_vectorstore(docstore, document_embedder) + if ds: + try: + logger.info(f"Getting retrieved top k values: {settings.retriever.top_k} with confidence threshold: {settings.retriever.score_threshold}") + retriever = ds.as_retriever(search_type="similarity_score_threshold",search_kwargs={"score_threshold": settings.retriever.score_threshold,"k": settings.retriever.top_k}) + docs = retriever.invoke(input=query, config={"callbacks":[self.cb_handler]}) + if not docs: + logger.warning("Retrieval failed to get any relevant context") + return iter(["No response generated from LLM, make sure your query is relavent to the ingested document."]) + + augmented_prompt = "Relevant documents:" + docs + "\n\n[[QUESTION]]\n\n" + query + system_prompt = settings.prompts.rag_template + logger.info(f"Formulated prompt for RAG chain: {system_prompt}\n{augmented_prompt}") + response = get_llm(model_name=RESPONSE_PARAPHRASING_MODEL, cb_handler=self.cb_handler, is_response_generator=True, **kwargs).chat_with_prompt(settings.prompts.rag_template, augmented_prompt) + return response + except Exception as e: + logger.info(f"Skipping similarity score as it's not supported by retriever") + retriever = ds.as_retriever() + docs = retriever.invoke(input=query, config={"callbacks":[self.cb_handler]}) + if not docs: + logger.warning("Retrieval failed to get any relevant context") + return iter(["No response generated from LLM, make sure your query is relavent to the ingested document."]) + docs=[doc.page_content for doc in docs] + docs = " ".join(docs) + augmented_prompt = "Relevant documents:" + docs + "\n\n[[QUESTION]]\n\n" + query + system_prompt = settings.prompts.rag_template + logger.info(f"Formulated prompt for RAG chain: {system_prompt}\n{augmented_prompt}") + response = get_llm(model_name=RESPONSE_PARAPHRASING_MODEL, cb_handler=self.cb_handler, is_response_generator=True, **kwargs).chat_with_prompt(settings.prompts.rag_template, augmented_prompt) + return response except Exception as e: logger.warning(f"Failed to generate response due to exception {e}") logger.warning( @@ -122,11 +136,12 @@ def document_search(self, content: str, num_docs: int) -> List[Dict[str, Any]]: """Search for the most relevant documents for the given search parameters.""" try: - retriever = get_doc_retriever(type="query") - context, sources = retriever.get_relevant_docs(content, limit=settings.retriever.top_k) + ds = get_vectorstore(docstore, document_embedder) + retriever = ds.as_retriever() + sources = retriever.invoke(input=content, limit=settings.retriever.top_k, config={"callbacks":[self.cb_handler]}) output = [] - for every_chunk in sources.values(): - entry = {"source": every_chunk['doc_metadata']['filename'], "content": every_chunk['doc_content']} + for every_chunk in sources: + entry = {"source": every_chunk.metadata['filename'], "content": every_chunk.page_content} output.append(entry) return output except Exception as e: @@ -135,14 +150,19 @@ def document_search(self, content: str, num_docs: int) -> List[Dict[str, Any]]: def get_documents(self): """Retrieves filenames stored in the vector store.""" - embedding_size = get_embedder(type="passage").get_embedding_size() - vector_db = get_vector_index(embedding_size) - decoded_filenames = vector_db.list_filenames() - return decoded_filenames + try: + ds = get_vectorstore(docstore, document_embedder) + if ds: + return get_docs_vectorstore_langchain(ds) + except Exception as e: + logger.error(f"Vectorstore not initialized. Error details: {e}") + return [] def delete_documents(self, filenames: List[str]): """Delete documents from the vector index.""" - embedding_size = get_embedder(type="passage").get_embedding_size() - vector_db = get_vector_index(embedding_size) - for each_file in filenames: - vector_db.delete_by_filename(each_file) \ No newline at end of file + try: + ds = get_vectorstore(docstore, document_embedder) + if ds: + return del_docs_vectorstore_langchain(ds, filenames) + except Exception as e: + logger.error(f"Vectorstore not initialized. Error details: {e}") diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/llm/llm_client.py b/RetrievalAugmentedGeneration/examples/multimodal_rag/llm/llm_client.py index 559641407..14997d0f2 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/llm/llm_client.py +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/llm/llm_client.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import logging +logger = logging.getLogger(__name__) + from RetrievalAugmentedGeneration.example.llm.llm import create_llm from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate @@ -23,10 +26,11 @@ class LLMClient: def __init__(self, model_name="mixtral_8x7b", model_type="NVIDIA", is_response_generator=False, cb_handler=BaseCallbackHandler, **kwargs): self.llm = create_llm(model_name, model_type, is_response_generator, **kwargs) self.cb_handler = cb_handler - + def chat_with_prompt(self, system_prompt, prompt): langchain_prompt = ChatPromptTemplate.from_messages([("system", system_prompt), ("user", "{input}")]) chain = langchain_prompt | self.llm | StrOutputParser() + logger.info(f"Prompt used for response generation: {langchain_prompt.format(input=prompt)}") response = chain.stream({"input": prompt}, config={"callbacks": [self.cb_handler]}) return response diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/requirements.txt b/RetrievalAugmentedGeneration/examples/multimodal_rag/requirements.txt index 0f43b859c..f1d7a09f7 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/requirements.txt +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/requirements.txt @@ -1,8 +1,10 @@ -pymupdf==1.23.15 +pdfplumber==0.11.0 gspread==6.0.0 pandas==2.2.0 Pillow==10.2.0 pydantic==2.5.3 pymilvus==2.3.5 -python_pptx==0.6.23 -Requests==2.31.0 \ No newline at end of file +python-pptx==0.6.23 +Requests==2.31.0 +opencv-python== 4.9.0.80 +pytesseract==0.3.10 \ No newline at end of file diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/retriever/vector.py b/RetrievalAugmentedGeneration/examples/multimodal_rag/retriever/vector.py index aab9683d2..a8af767ec 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/retriever/vector.py +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/retriever/vector.py @@ -155,7 +155,7 @@ def list_filenames(self): List all filenames in the collection. """ # Assuming 'filename' is a field in the metadata - + expr = "metadata['filename'] != ''" # Expression to match all entities with a non-empty filename entities = self.vector_db.query(expr, output_fields=["metadata"]) filenames = list(set([entity['metadata']['filename'] for entity in entities])) @@ -169,4 +169,4 @@ def delete_by_filename(self, filename): expr = f"metadata['filename'] == '{filename}'" self.vector_db.delete(expr) # Load the collection to make the deletion take effect - self.vector_db.load() + self.vector_db.load() diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_pdf_parser.py b/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_pdf_parser.py index c54753764..cec1b40fb 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_pdf_parser.py +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_pdf_parser.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import fitz +from pdfplumber import open as pdf_open import pandas as pd import os from langchain.docstore.document import Document @@ -22,6 +22,8 @@ from PIL import Image from io import BytesIO import base64 +import cv2 +import pytesseract from RetrievalAugmentedGeneration.common.tracing import langchain_instrumentation_method_wrapper def get_b64_image(image_path): @@ -31,6 +33,12 @@ def get_b64_image(image_path): b64_string = base64.b64encode(buffered.getvalue()).decode("utf-8") return b64_string +def is_bbox_overlapping(bbox1, bbox2): + return (bbox1[0]bbox2[0] and bbox1[1]>bbox2[3] and bbox1[3]bbox2[0] and bbox1[1]>bbox2[3] and bbox1[3]= -horizontal_threshold_distance: - if block_bbox.y1 < bbox.y0 and not before_text: - before_text = block[4] - elif block_bbox.y0 > bbox.y1 and not after_text: - after_text = block[4] + if block['y1'] < bbox[1] and not before_text: + before_text = block['text'] + elif block['y0'] > bbox[2] and not after_text: + after_text = block['text'] break return before_text, after_text - def process_text_blocks(text_blocks): char_count_threshold = 500 # Threshold for the number of characters in a group current_group = [] grouped_blocks = [] current_char_count = 0 - for block in text_blocks: - if block[-1] == 0: # Check if the block is of text type - block_text = block[4] + if block['object_type'] in ('char','str'): # Check if the block is of text type + block_text = block['text'] block_char_count = len(block_text) if current_char_count + block_char_count <= char_count_threshold: @@ -101,170 +127,195 @@ def process_text_blocks(text_blocks): current_char_count += block_char_count else: if current_group: - grouped_content = "\n".join([b[4] for b in current_group]) + grouped_content = " ".join([b['text'] for b in current_group]) grouped_blocks.append((current_group[0], grouped_content)) current_group = [block] current_char_count = block_char_count # Append the last group if current_group: - grouped_content = "\n".join([b[4] for b in current_group]) + grouped_content = "".join([b['text'] for b in current_group]) grouped_blocks.append((current_group[0], grouped_content)) return grouped_blocks +def parse_via_ocr(filename, page, pagenum): + ocr_docs = [] + ocr_image = page.to_image(resolution=109) + imgrefpath = os.path.join("/tmp-data", "multimodal/ocr_references") + if not os.path.exists(imgrefpath): + os.makedirs(imgrefpath) + image_path = os.path.join(imgrefpath, f"page{pagenum}.png") + ocr_image.save(image_path) + img = cv2.imread(image_path) + ocr_text = pytesseract.image_to_string(img) + ocr_metadata = { + "x1":0, + "y1":0, + "x2":0, + "x3":0, + "source": f"{os.path.basename(filename)}", + "image": image_path, + "caption": ocr_text, + "type": "image", + "page_num": pagenum + } + + ocr_docs.append(Document(page_content="This is a page with text: " + ocr_text, metadata=ocr_metadata)) + return ocr_docs + def parse_all_tables(filename, page, pagenum, text_blocks, ongoing_tables): table_docs = [] table_bboxes = [] ctr = 1 - try: - tables = page.find_tables(horizontal_strategy = "lines_strict", vertical_strategy = "lines_strict") + try: + tables = page.find_tables(table_settings={"horizontal_strategy":"lines_strict", "vertical_strategy":"lines_strict"}) except Exception as e: print(f"Error during table extraction: {e}") return table_docs, table_bboxes, ongoing_tables if tables: - for tab in tables: - if tab.header.external: - # Check if this table is a continuation of a table from a previous page - previous_table = ongoing_tables.get(pagenum - 1, None) - if previous_table: - # Merge the current table with the previous part - combined_df = pd.concat([previous_table['dataframe'], tab.to_pandas()]) - ongoing_tables[pagenum] = {"dataframe": combined_df, "bbox": bbox} - continue - if not tab.header.external: - pandas_df = tab.to_pandas() - tablerefdir = os.path.join(os.getcwd(), "multimodal/table_references") - if not os.path.exists(tablerefdir): - os.makedirs(tablerefdir) - df_xlsx_path = os.path.join(tablerefdir, f"table{ctr}-page{pagenum}.xlsx") - pandas_df.to_excel(df_xlsx_path) - bbox = fitz.Rect(tab.bbox) - table_bboxes.append(bbox) - - # Find text around the table - before_text, after_text = extract_text_around_item(text_blocks, bbox, page.rect.height) - - table_img = page.get_pixmap(clip=bbox) - table_img_path = os.path.join(tablerefdir, f"table{ctr}-page{pagenum}.jpg") - table_img.save(table_img_path) - description = process_graph(table_img_path) - ctr += 1 - - caption = before_text.replace("\n", " ") + description + after_text.replace("\n", " ") - if before_text == "" and after_text == "": - caption = " ".join(tab.header.names) - - - table_metadata = { - "source": f"{filename[:-4]}-page{pagenum}-table{ctr}", - "dataframe": df_xlsx_path, - "image": table_img_path, - "caption": caption, - "type": "table", - "page_num": pagenum - } - all_cols = ", ".join(list(pandas_df.columns.values)) - doc = Document(page_content="This is a table with the caption: " + caption + f"\nThe columns are {all_cols}", metadata=table_metadata) - table_docs.append(doc) + for table_num, table in enumerate(tables, start=1): + try: + tablerefdir = os.path.join("/tmp-data", "vectorstore/table_references") + if not os.path.exists(tablerefdir): + os.makedirs(tablerefdir) + df_xlsx_path = os.path.join(tablerefdir, f"table{table_num}-page{pagenum}.xlsx") + page_crop=page.crop(table.bbox) + if len(page_crop.extract_tables())>0: + table_df_text = page_crop.extract_tables()[0] + table_df = text_to_table(table_df_text) + table_df.to_excel(df_xlsx_path) + # Find text around the table + table_bbox = table.bbox + before_text, after_text = extract_text_around_item(text_blocks, table_bbox, page.height) + # Save table image + table_img_path = os.path.join(tablerefdir, f"table{table_num}-page{pagenum}.jpg") + img = page_crop.to_image(resolution=109) + img.save(table_img_path) + description = process_graph(table_img_path) + ctr +=1 + caption = before_text.replace("\n", " ") + description + after_text.replace("\n", " ") + if before_text == "" and after_text == "": + caption = " ".join(table_df.columns) + table_data_text = stringify_table(table_df_text) + table_metadata = { + "x1":0, + "y1":0, + "x2":0, + "x3":0, + "source": f"{os.path.basename(filename)}", + "dataframe": df_xlsx_path, + "image": table_img_path, + "caption": caption, + "type": "table", + "page_num": pagenum + 1 + } + all_cols = ", ".join(list(table_df.columns.values)) + doc = Document(page_content="This is a table with the caption: " + caption + f"\nThe columns are {all_cols} and the table data is {table_data_text}", metadata=table_metadata) + table_docs.append(doc) + except: + print(f"Skipping Table {table_num} due to Exception {e}") return table_docs, table_bboxes, ongoing_tables def parse_all_images(filename, page, pagenum, text_blocks): image_docs = [] - image_info_list = page.get_image_info(xrefs=True) - page_rect = page.rect # Get the dimensions of the page - - for image_info in image_info_list: - xref = image_info['xref'] - if xref == 0: - continue # Skip inline images or undetectable images - - img_bbox = fitz.Rect(image_info['bbox']) - # Check if the image size is at least 5% of the page size in any dimension - if img_bbox.width < page_rect.width / 20 or img_bbox.height < page_rect.height / 20: - continue # Skip very small images + image_list = page.images + # image_info_list = page.get_image_info(xrefs=True) + # page_rect = page.rect # Get the dimensions of the page + + for image_num, image in enumerate(image_list): + # xref = image_info['xref'] + # if xref == 0: + # continue # Skip inline images or undetectable images + image_bbox = (image['x0'],image['y0'], image['x1'],image['y1']) + # Check if the image size is at least 5% of the page size in any dimension + if image["width"] < page.width / 20 or image["height"] < page.height / 20: + continue # Skip very small images + + # Extract and save the image + page_crop = page.crop(image_bbox,strict=False) + image_data = page_crop.to_image() + imgrefpath = os.path.join("/tmp-data", "multimodal/image_references") + if not os.path.exists(imgrefpath): + os.makedirs(imgrefpath) + image_path = os.path.join(imgrefpath, f"image{image_num}-page{pagenum}.png") + image_data.save(image_path) + # Find text around the image + before_text, after_text = extract_text_around_item(text_blocks, image_bbox, page.height) + # skip images without a caption, they are likely just some logo or graphics + if before_text == "" and after_text == "": + continue - # Extract and save the image - extracted_image = page.parent.extract_image(xref) - image_data = extracted_image["image"] - imgrefpath = os.path.join(os.getcwd(), "multimodal/image_references") - if not os.path.exists(imgrefpath): - os.makedirs(imgrefpath) - image_path = os.path.join(imgrefpath, f"image{xref}-page{pagenum}.png") - with open(image_path, "wb") as img_file: - img_file.write(image_data) + # Process the image if it's a graph + image_description = " " + if is_graph(image_path): + image_description = process_graph(image_path) - # Find text around the image - before_text, after_text = extract_text_around_item(text_blocks, img_bbox, page.rect.height) - # skip images without a caption, they are likely just some logo or graphics - if before_text == "" and after_text == "": - continue + # Combine the texts to form a caption + caption = before_text.replace("\n", " ") + image_description + after_text.replace("\n", " ") - # Process the image if it's a graph - image_description = " " - if is_graph(image_path): - image_description = process_graph(image_path) + image_metadata = { + "x1":0, + "y1":0, + "x2":0, + "x3":0, + "source": f"{os.path.basename(filename)}", + "image": image_path, + "caption": caption, + "type": "image", + "page_num": pagenum + } - # Combine the texts to form a caption - caption = before_text.replace("\n", " ") + image_description + after_text.replace("\n", " ") + image_docs.append(Document(page_content="This is an image with the caption: " + caption, metadata=image_metadata)) - image_metadata = { - "source": f"{filename[:-4]}-page{pagenum}-image{xref}", - "image": image_path, - "caption": caption, - "type": "image", - "page_num": pagenum - } - image_docs.append(Document(page_content="This is an image with the caption: " + caption, metadata=image_metadata)) return image_docs def get_pdf_documents(filepath): all_pdf_documents = [] ongoing_tables = {} try: - f = fitz.open(filepath) + f = pdf_open(filepath) except Exception as e: print(f"Error opening or processing the PDF file: {e}") return [] - - for i in range(len(f)): - page = f[i] - page_docs = [] - - # Process text blocks - initial_text_blocks = page.get_text("blocks", sort=True) - - # Define thresholds for header and footer (10% of the page height) - page_height = page.rect.height - header_threshold = page_height * 0.1 - footer_threshold = page_height * 0.9 - - # Filter out text blocks that are likely headers or footers - text_blocks = [block for block in initial_text_blocks if block[-1] == 0 and not (block[1] < header_threshold or block[3] > footer_threshold)] - - # Group text blocks by character count - grouped_text_blocks = process_text_blocks(text_blocks) - - # Extract tables and their bounding boxes - table_docs, table_bboxes, ongoing_tables = parse_all_tables(filepath, page, i, text_blocks, ongoing_tables) - page_docs.extend(table_docs) - - # Extract and process images - image_docs = parse_all_images(filepath, page, i, text_blocks) - page_docs.extend(image_docs) - - # Process grouped text blocks - text_block_ctr = 0 - for heading_block, content in grouped_text_blocks: - text_block_ctr +=1 - heading_bbox = fitz.Rect(heading_block[:4]) - # Check if the heading or its content overlaps with table or image bounding boxes - if not any(heading_bbox.intersects(table_bbox) for table_bbox in table_bboxes): - bbox = {"x1": heading_block[0], "y1": heading_block[1], "x2": heading_block[2], "x3": heading_block[3]} - text_doc = Document(page_content=f"{heading_block[4]}\n{content}", metadata={**bbox, "type": "text", "page_num": i, "source": f"{filepath[:-4]}-page{i}-block{text_block_ctr}"}) - page_docs.append(text_doc) - - all_pdf_documents.append(page_docs) - + for page_num, page in enumerate(f.pages): + try: + page_docs = [] + + # Define thresholds for header and footer (10% of the page height) + page_height = page.height + header_threshold = page_height * 0.1 + footer_threshold = page_height * 0.9 + + # Crop out page to remove footers and headers + page_crop = page.crop([0,header_threshold,page.width,footer_threshold]) + text_blocks = [obj for obj in page_crop.chars if obj['object_type'] == 'char'] + grouped_text_blocks = process_text_blocks(text_blocks) + + if len(grouped_text_blocks)==0: + # Perform OCR on PDF pages + ocr_docs = parse_via_ocr(filepath, page_crop, page_num) + page_docs.extend(ocr_docs) + # Extract tables and their bounding boxes + table_docs, table_bboxes, ongoing_tables = parse_all_tables(filepath, page, page_num, text_blocks, ongoing_tables) + page_docs.extend(table_docs) + + # Extract and process images + image_docs = parse_all_images(filepath, page, page_num, text_blocks) + page_docs.extend(image_docs) + + # Process text blocks + text_block_ctr = 0 + for heading_block, content in grouped_text_blocks: + text_block_ctr +=1 + heading_bbox = (heading_block['x0'],heading_block['y0'],heading_block['x1'],heading_block['y1']) + # Check if the heading or its content overlaps with table or image bounding boxes + if not any(is_bbox_overlapping(heading_bbox,table_bbox) for table_bbox in table_bboxes): + bbox = {"x1": heading_bbox[0], "y1": heading_bbox[1], "x2": heading_bbox[2], "x3": heading_bbox[3]} + text_doc = Document(page_content=f"{heading_block['text']}\n{content}", metadata={**bbox, "type": "text", "page_num": page_num, "source": f"{os.path.basename(filepath)}"}) + page_docs.append(text_doc) + all_pdf_documents.append(page_docs) + except Exception as e: + print(f"Skipping the page {page_num} due to Exception {e}") f.close() return all_pdf_documents diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_powerpoint_parser.py b/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_powerpoint_parser.py index d5531a369..791a7d5dc 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_powerpoint_parser.py +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/custom_powerpoint_parser.py @@ -16,7 +16,7 @@ import os import subprocess from pptx import Presentation -import fitz +from pdfplumber import open as pdf_open from langchain.docstore.document import Document from RetrievalAugmentedGeneration.example.vectorstore.custom_pdf_parser import is_graph, process_graph @@ -24,7 +24,7 @@ def convert_ppt_to_pdf(ppt_path): """Convert a PowerPoint file to PDF using LibreOffice and save in '../../ppt_references/' folder.""" base_name = os.path.basename(ppt_path) - ppt_name_without_ext = os.path.splitext(base_name)[0].replace(' ', '_') + ppt_name_without_ext = os.path.splitext(base_name)[0].replace(" ", "_") # Use the existing directory '../../ppt_references/' new_dir_path = os.path.abspath("multimodal/ppt_references") @@ -38,22 +38,22 @@ def convert_ppt_to_pdf(ppt_path): return pdf_path + def convert_pdf_to_images(pdf_path): """Convert a PDF file to a series of images using PyMuPDF and save in '../../ppt_references/' folder.""" - doc = fitz.open(pdf_path) + doc = pdf_open(pdf_path) # Extract the base name of the PDF file and replace spaces with underscores base_name = os.path.basename(pdf_path) - pdf_name_without_ext = os.path.splitext(base_name)[0].replace(' ', '_') + pdf_name_without_ext = os.path.splitext(base_name)[0].replace(" ", "_") # Use the existing directory '../../ppt_references/' new_dir_path = os.path.join(os.getcwd(), "multimodal/ppt_references") image_paths = [] - for page_num in range(len(doc)): - page = doc.load_page(page_num) - pix = page.get_pixmap() + for page_num, page in enumerate(doc.pages): + pix = page.to_image() # Save images in the existing directory output_image_path = os.path.join(new_dir_path, f"{pdf_name_without_ext}_{page_num:04d}.png") @@ -63,6 +63,7 @@ def convert_pdf_to_images(pdf_path): doc.close() return image_paths + def extract_text_and_notes_from_ppt(ppt_path): """Extract text and notes from a PowerPoint file.""" prs = Presentation(ppt_path) @@ -70,12 +71,13 @@ def extract_text_and_notes_from_ppt(ppt_path): for slide in prs.slides: slide_text = ' '.join([shape.text for shape in slide.shapes if hasattr(shape, "text")]) try: - notes = slide.notes_slide.notes_text_frame.text if slide.notes_slide else '' + notes = slide.notes_slide.notes_text_frame.text if slide.notes_slide else "" except: - notes = '' + notes = "" text_and_notes.append((slide_text, notes)) return text_and_notes + def process_ppt_file(ppt_path): """Process a PowerPoint file.""" pdf_path = os.path.join(os.getcwd(), "multimodal/ppt_references", os.path.basename(ppt_path).replace('.pptx', '.pdf').replace('.ppt', '.pdf')) @@ -92,14 +94,18 @@ def process_ppt_file(ppt_path): image_description = " " if is_graph(image_path): image_description = process_graph(image_path) - + caption = slide_text + image_description + notes image_metadata = { - "source": f"{os.path.basename(ppt_path)}", - "image": image_path, - "caption": slide_text + image_description + notes, - "type": "image", - "page_num": page_num + "x1":0, + "y1":0, + "x2":0, + "x3":0, + "source": f"{os.path.basename(ppt_path)}", + "image": image_path, + "caption": caption, + "type": "image", + "page_num": page_num } processed_data.append(Document(page_content = "This is a slide with the text: " + slide_text + image_description, metadata = image_metadata)) - return processed_data + return processed_data \ No newline at end of file diff --git a/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/vectorstore_updater.py b/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/vectorstore_updater.py index 1297761a0..9e833db4d 100644 --- a/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/vectorstore_updater.py +++ b/RetrievalAugmentedGeneration/examples/multimodal_rag/vectorstore/vectorstore_updater.py @@ -17,7 +17,6 @@ import os from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import UnstructuredFileLoader - from RetrievalAugmentedGeneration.example.vectorstore.custom_powerpoint_parser import process_ppt_file from RetrievalAugmentedGeneration.example.vectorstore.custom_pdf_parser import get_pdf_documents @@ -74,17 +73,10 @@ def update_vectorstore(file_path, vector_client, embedder, config_name): documents = split_text(raw_documents) # Adding file name to the metadata - extract_filename = lambda filepath : os.path.splitext(os.path.basename(filepath))[0] for document in documents: - document.metadata["filename"] = extract_filename(file_path) + document.metadata["filename"] = os.path.basename(file_path) logger.info("[Step 3/4] Inserting documents into the vector store...") - # Extracting the page content from each document - document_contents = [doc.page_content for doc in documents] - - # Embedding the documents using the updated embedding function - document_embeddings = embedder.embed_documents(document_contents, batch_size=10) - # Batch insert into Milvus collection - vector_client.update(documents, document_embeddings, config_name) + vector_client.add_documents(documents) logger.info("[Step 4/4] Saved vector store!") diff --git a/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/chains.py b/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/chains.py index ba41b4a63..82f330174 100644 --- a/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/chains.py +++ b/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/chains.py @@ -29,7 +29,6 @@ from RetrievalAugmentedGeneration.common.tracing import langchain_instrumentation_class_wrapper logger = logging.getLogger(__name__) -DOCS_DIR = os.path.abspath("./uploaded_files") vector_store_path = "vectorstore.pkl" document_embedder = get_embedding_model() text_splitter = None @@ -49,8 +48,7 @@ def ingest_docs(self, filepath: str, filename: str): raise ValueError(f"{filename} is not a valid Text, PDF or Markdown file") try: # Load raw documents from the directory - # Data is copied to `DOCS_DIR` in common.server:upload_document - _path = os.path.join(DOCS_DIR, filename) + _path = filepath raw_documents = UnstructuredFileLoader(_path).load() if raw_documents: @@ -92,6 +90,7 @@ def llm_chain( augmented_user_input = ( "\n\nQuestion: " + query + "\n" ) + logger.info(f"Prompt used for response generation: {prompt_template.format(input=augmented_user_input)}") return chain.stream({"input": augmented_user_input}, config={"callbacks":[self.cb_handler]}) def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Generator[str, None, None]: @@ -127,6 +126,7 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene retriever = vs.as_retriever() docs = retriever.get_relevant_documents(query, callbacks=[self.cb_handler]) + logger.debug(f"Retrieved documents are: {docs}") if not docs: logger.warning("Retrieval failed to get any relevant context") return iter(["No response generated from LLM, make sure your query is relavent to the ingested document."]) @@ -139,6 +139,7 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene "Context: " + context + "\n\nQuestion: " + query + "\n" ) + logger.info(f"Prompt used for response generation: {prompt_template.format(input=augmented_user_input)}") return chain.stream({"input": augmented_user_input}, config={"callbacks":[self.cb_handler]}) except Exception as e: logger.warning(f"Failed to generate response due to exception {e}") diff --git a/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/requirements.txt b/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/requirements.txt deleted file mode 100644 index 39556ee63..000000000 --- a/RetrievalAugmentedGeneration/examples/nvidia_api_catalog/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -faiss-cpu==1.7.4 \ No newline at end of file diff --git a/RetrievalAugmentedGeneration/examples/query_decomposition_rag/chains.py b/RetrievalAugmentedGeneration/examples/query_decomposition_rag/chains.py index a09acc398..1a5b9a084 100644 --- a/RetrievalAugmentedGeneration/examples/query_decomposition_rag/chains.py +++ b/RetrievalAugmentedGeneration/examples/query_decomposition_rag/chains.py @@ -16,7 +16,7 @@ """ This example showcases recursive task decomposition to perform RAG which requires multiple steps. The agent is a langchain custom LLM agent, which uses 2 tools - search and math. -It uses OpenAI's GPT-4 model for sub-answer formation, tool prediction and math operations. It uses the deployed LLM for final answer formation. +It uses Llama3 model for sub-answer formation, tool prediction and math operations. Search tool is a RAG pipeline, whereas the math tool uses an LLM call to perform mathematical calculations. """ @@ -55,7 +55,6 @@ logger = logging.getLogger(__name__) -DOCS_DIR = os.path.abspath("./uploaded_files") vector_store_path = "vectorstore.pkl" document_embedder = get_embedding_model() settings = get_config() @@ -89,9 +88,10 @@ def fetch_context(ledger: Ledger) -> str: return context template = """Your task is to answer questions. If you cannot answer the question, you can request use for a tool and break the question into specific sub questions. Fill with Nil where no action is required. You should only return a JSON containing the tool and the generated sub questions. Consider the contextual information and only ask for information that you do not already have. Do not return any other explanations or text. The output should be a simple JSON structure! You are given two tools: -- Search tool -- Math tool - +- Search +- Math +Search tool quickly finds and retrieves relevant answers from a given context, providing accurate and precise information to meet search needs. +Math tool performs essential operations, including multiplication, addition, subtraction, division, and greater than or less than comparisons, providing accurate results with ease. Utilize math tool when asked to find sum, difference of values. Do not pass sub questions to any tool if they already have an answer in the Contextual Information. If you have all the information needed to answer the question, mark the Tool_Request as Nil. @@ -104,6 +104,32 @@ def fetch_context(ledger: Ledger) -> str: {"Tool_Request": "", "Generated Sub Questions": []} """ +math_tool_prompt = """Your task is to identify 2 variables and an operation from given questions. If you cannot answer the question, you can simply return "Not Possible". You should only return a JSON containing the `IsPossible`, `variable1`, `variable2`, and `operation`. Do not return any other explanations or text. The output should be a simple JSON structure! + You are given two options for `IsPossible`: +- Possible +- Not Possible + `variable1` and `variable2` should be real floating point numbers. + You are given four options for `operation symbols`: +- '+' (addition) +- '-' (subtraction) +- '*' (multiplication) +- '/' (division) +- '=' (equal to) +- '>' (greater than) +- '<' (less than) +- '>=' (greater than or equal to) +- '<=' (less than or equal to) + Only return the symbols for the specified operations and nothing else. +Contextual Information: +{{ context }} + +Question: +{{ question }} + +{"IsPossible": "", "variable1": [], "variable2": [], "operation": []} +""" + + class CustomPromptTemplate(BaseChatPromptTemplate): template: str tools: List[Tool] @@ -147,10 +173,10 @@ def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]: log=llm_output, ) - if local_state["Tool_Request"] == "Search tool": + if local_state["Tool_Request"] == "Search": self.ledger.trace += 1 - if local_state["Tool_Request"] in ["Search tool", "Math tool"]: + if local_state["Tool_Request"] in ["Search", "Math"]: return AgentAction( tool=local_state["Tool_Request"], tool_input={"sub_questions": local_state["Generated Sub Questions"]}, @@ -166,8 +192,7 @@ def ingest_docs(self, filepath: str, filename: str): raise ValueError(f"{filename} is not a valid Text, PDF or Markdown file") try: # Load raw documents from the directory - # Data is copied to `DOCS_DIR` in common.server:upload_document - _path = os.path.join(DOCS_DIR, filename) + _path = filepath raw_documents = UnstructuredFileLoader(_path).load() if raw_documents: @@ -206,6 +231,7 @@ def llm_chain( augmented_user_input = ( "\n\nQuestion: " + query + "\n" ) + logger.info(f"Prompt used for response generation: {prompt_template.format(input=augmented_user_input)}") return chain.stream({"input": augmented_user_input}, config={"callbacks":[self.cb_handler]}) def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Generator[str, None, None]: @@ -228,7 +254,7 @@ def rag_chain(self, query: str, chat_history: List["Message"], **kwargs) -> Gene ) llm = get_llm(**kwargs) chain = final_prompt_template | llm | StrOutputParser() - + logger.info(f"Prompt used for final response generation: {final_prompt_template}") return chain.stream({}, config={"callbacks":[self.cb_handler]}) except ValueError as e: logger.warning(f"Failed to get response because {e}") @@ -244,8 +270,8 @@ def create_agent(self, **kwargs) -> AgentExecutor: self.kwargs = kwargs tools = [ - Tool(name="Search tool", func=self.search, description="Searches for the answer from a given context."), - Tool(name="Math tool", func=self.math, description="Performs mathematical calculations."), + Tool(name="Search", func=self.search, description="The Search Tool is a powerful querying system that quickly finds and retrieves relevant answers from a given context, providing accurate and precise information to meet your search needs."), + Tool(name="Math", func=self.math, description="The Math Tool is a versatile calculator that performs essential mathematical operations, including multiplication, addition, subtraction, division, and greater than or less than comparisons, providing accurate results with ease."), ] tool_names = [tool.name for tool in tools] @@ -295,7 +321,7 @@ def retriever(self, query: str) -> List[str]: # Currently it's raising an error during invoke. retriever = vs.as_retriever() result = retriever.get_relevant_documents(query, callbacks=[self.cb_handler]) - logger.info(result) + logger.debug(result) return [hit.page_content for hit in result] @@ -332,16 +358,28 @@ def math(self, sub_questions: List[str]): """ Places an LLM call to answer mathematical subquestions which do not require search """ + try: + prompt = f"{math_tool_prompt}\nQuestion: {sub_questions[0]}" + prompt += f"Context:\n{fetch_context(self.ledger)}\n" + logger.info(f"Performing Math LLM call with prompt: {prompt}") + llm = get_llm(**self.kwargs) + sub_answer = llm([HumanMessage(content=prompt)]) + sub_answer = json.loads(sub_answer.content) + final_sub_answer= str(sub_answer['variable1'])+sub_answer['operation']+str(sub_answer['variable2']) + final_sub_answer=final_sub_answer+'='+str(eval(final_sub_answer)) + except: + prompt = "Solve this mathematical question:\nQuestion: " + sub_questions[0] + prompt += f"Context:\n{fetch_context(self.ledger)}\n" + prompt += "Be concise and only return the answer." + + logger.info(f"Performing Math LLM call with prompt: {prompt}") + llm = get_llm(**self.kwargs) + sub_answer = llm([HumanMessage(content=prompt)]) + final_sub_answer = sub_answer.content - prompt = "Solve this mathematical question:\nQuestion: " + sub_questions[0] - prompt += f"Context:\n{fetch_context(self.ledger)}\n" - prompt += "Be concise and only return the answer." - logger.info(f"Performing Math LLM call with prompt: {prompt}") - llm = get_llm(**self.kwargs) - sub_answer = llm([HumanMessage(content=prompt)]) self.ledger.question_trace.append(sub_questions[0]) - self.ledger.answer_trace.append(sub_answer.content) + self.ledger.answer_trace.append(final_sub_answer) self.ledger.done = True diff --git a/RetrievalAugmentedGeneration/examples/query_decomposition_rag/requirements.txt b/RetrievalAugmentedGeneration/examples/query_decomposition_rag/requirements.txt deleted file mode 100644 index 39556ee63..000000000 --- a/RetrievalAugmentedGeneration/examples/query_decomposition_rag/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -faiss-cpu==1.7.4 \ No newline at end of file diff --git a/RetrievalAugmentedGeneration/examples/structured_data_rag/chains.py b/RetrievalAugmentedGeneration/examples/structured_data_rag/chains.py index 2f2b3066f..d322bbccb 100644 --- a/RetrievalAugmentedGeneration/examples/structured_data_rag/chains.py +++ b/RetrievalAugmentedGeneration/examples/structured_data_rag/chains.py @@ -106,12 +106,12 @@ def read_and_concatenate_csv(self, file_paths_txt): def ingest_docs(self, filepath: str, filename: str): """Ingest documents to the VectorDB.""" - + if not filename.endswith(".csv"): raise ValueError(f"{filename} is not a valid CSV file") with open(INGESTED_CSV_FILES_LIST, "a+", encoding="UTF-8") as f: - + ref_csv_path = None try: @@ -152,8 +152,7 @@ def llm_chain( system_message + user_input ) - logger.info("Using prompt for response: %s", prompt) - + logger.info(f"Using prompt for response generation: {prompt.format(input=query)}") chain = prompt | get_llm(**kwargs) | StrOutputParser() return chain.stream({"input": query}) @@ -241,4 +240,5 @@ def get_documents(self) -> List[str]: def delete_documents(self, filenames: List[str]): """Delete documents from the vector index.""" - logger.error("delete_documents not implemented") \ No newline at end of file + logger.error("delete_documents not implemented") + return True \ No newline at end of file diff --git a/RetrievalAugmentedGeneration/frontend/Dockerfile b/RetrievalAugmentedGeneration/frontend/Dockerfile index 24d85ea55..4fe4e64c1 100644 --- a/RetrievalAugmentedGeneration/frontend/Dockerfile +++ b/RetrievalAugmentedGeneration/frontend/Dockerfile @@ -1,5 +1,5 @@ ARG BASE_IMAGE_URL=nvcr.io/nvidia/base/ubuntu -ARG BASE_IMAGE_TAG=20.04_x64_2022-09-23 +ARG BASE_IMAGE_TAG=22.04_20240212 FROM ${BASE_IMAGE_URL}:${BASE_IMAGE_TAG} diff --git a/RetrievalAugmentedGeneration/frontend/frontend/chat_client.py b/RetrievalAugmentedGeneration/frontend/frontend/chat_client.py index 406757363..19d8c42a6 100644 --- a/RetrievalAugmentedGeneration/frontend/frontend/chat_client.py +++ b/RetrievalAugmentedGeneration/frontend/frontend/chat_client.py @@ -34,7 +34,7 @@ def __init__(self, server_url: str, model_name: str) -> None: """Initialize the client.""" self.server_url = server_url self._model_name = model_name - self.default_model = "llama2-7B-chat" + self.default_model = "meta/llama3-70b-instruct" @property def model_name(self) -> str: @@ -83,13 +83,6 @@ def predict( } ], "use_knowledge_base": use_knowledge_base, - "temperature": 0.2, - "top_p": 0.7, - "max_tokens": num_tokens, - "seed": 42, - "bad": ["string"], - "stop": ["string"], - "stream": True } url = f"{self.server_url}/generate" _LOGGER.debug( diff --git a/RetrievalAugmentedGeneration/frontend/frontend/configuration.py b/RetrievalAugmentedGeneration/frontend/frontend/configuration.py index c1a7333ac..864ae45b8 100644 --- a/RetrievalAugmentedGeneration/frontend/frontend/configuration.py +++ b/RetrievalAugmentedGeneration/frontend/frontend/configuration.py @@ -39,6 +39,6 @@ class AppConfig(ConfigWizard): ) model_name: str = configfield( "modelName", - default="llama2-7B-chat", + default="meta/llama3-70b-instruct", help_txt="The name of the hosted LLM model.", ) diff --git a/RetrievalAugmentedGeneration/frontend/frontend/pages/kb.py b/RetrievalAugmentedGeneration/frontend/frontend/pages/kb.py index e30bc5b48..b66a2819f 100644 --- a/RetrievalAugmentedGeneration/frontend/frontend/pages/kb.py +++ b/RetrievalAugmentedGeneration/frontend/frontend/pages/kb.py @@ -57,7 +57,7 @@ def build_page(client: chat_client.ChatClient) -> gr.Blocks: message_textbox = gr.Textbox( label="Message", interactive=False, visible=True ) - + with gr.Row(): delete_button = gr.Button("Delete") diff --git a/RetrievalAugmentedGeneration/frontend/frontend/tts_utils.py b/RetrievalAugmentedGeneration/frontend/frontend/tts_utils.py index 1ca4d62ea..2266c138f 100644 --- a/RetrievalAugmentedGeneration/frontend/frontend/tts_utils.py +++ b/RetrievalAugmentedGeneration/frontend/frontend/tts_utils.py @@ -101,10 +101,10 @@ def text_to_speech(text, language, voice, enable_tts): tts_client = riva.client.SpeechSynthesisService(grpc_auth) _LOGGER.info(f"Calling synthesize_online") - - # To manage the 400-character limit for Riva's text-to-speech (TTS), longer answers are segmented by adding 'full stops' at every 400 characters - for i in range(len(text)//400): - indx = text.rfind(' ',i*400) + + # To manage the 400-character limit for Riva's text-to-speech (TTS), longer answers are segmented by adding 'full stops' at every 300 characters (300 instead of 400 to take in account phoneme expansion) + for i in range((len(text)//300)+1): + indx = text.rfind(' ',0,(i+1)*300) text = text[:indx]+' . '+text[indx:] response = tts_client.synthesize_online( diff --git a/RetrievalAugmentedGeneration/llm-inference-server/Dockerfile b/RetrievalAugmentedGeneration/llm-inference-server/Dockerfile deleted file mode 100644 index ef47aa245..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -ARG BASE_IMAGE_URL=nvcr.io/nvidia/nemo/nemofw-inference -ARG BASE_IMAGE_TAG=23.10-for-rag - -FROM ${BASE_IMAGE_URL}:${BASE_IMAGE_TAG} - -ENV LD_LIBRARY_PATH=/opt/tritonserver/backends/tensorrtllm:$LD_LIBRARY_PATH - -# install model-server automation -COPY conversion_scripts /opt/conversion_scripts -COPY ensemble_models /opt/ensemble_models -COPY model_server /opt/model_server -COPY model_server_client /opt/model_server_client -RUN --mount=type=bind,source=requirements.txt,target=/opt/requirements.txt \ - pip install --no-cache-dir -r /opt/requirements.txt - -# Create basic directories - -RUN mkdir /model && chmod 1777 /model && \ - mkdir -p /home/triton-server && chown 1000:1000 /home/triton-server && chmod 700 /home/triton-server - -WORKDIR /opt -ENTRYPOINT ["/usr/bin/python3", "-m", "model_server"] diff --git a/RetrievalAugmentedGeneration/llm-inference-server/conversion_scripts/llama/build.py b/RetrievalAugmentedGeneration/llm-inference-server/conversion_scripts/llama/build.py deleted file mode 100644 index 2a57d4cdb..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/conversion_scripts/llama/build.py +++ /dev/null @@ -1,776 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import argparse -import json -import os -import time -from pathlib import Path - -import tensorrt as trt -import tensorrt_llm -import torch -import torch.multiprocessing as mp -from tensorrt_llm._utils import str_dtype_to_trt -from tensorrt_llm.builder import Builder -from tensorrt_llm.layers.attention import PositionEmbeddingType -from tensorrt_llm.logger import logger -from tensorrt_llm.mapping import Mapping -from tensorrt_llm.models import ( - fp8_quantize, - smooth_quantize, - weight_only_groupwise_quantize, - weight_only_quantize, -) -from tensorrt_llm.network import net_guard -from tensorrt_llm.plugin.plugin import ContextFMHAType -from tensorrt_llm.quantization import QuantMode -from transformers import LlamaConfig, LlamaForCausalLM -from weight import ( - get_scaling_factors, - load_from_awq_llama, - load_from_binary, - load_from_gptq_llama, - load_from_hf_llama, - load_from_meta_llama, -) - -from weight import parse_ft_config # isort:skip - -MODEL_NAME = "llama" - -# 2 routines: get_engine_name, serialize_engine -# are direct copy from gpt example, TODO: put in utils? - -import onnx -import tensorrt as trt -from onnx import TensorProto, helper - - -def trt_dtype_to_onnx(dtype): - if dtype == trt.float16: - return TensorProto.DataType.FLOAT16 - elif dtype == trt.float32: - return TensorProto.DataType.FLOAT - elif dtype == trt.int32: - return TensorProto.DataType.INT32 - else: - raise TypeError("%s is not supported" % dtype) - - -def to_onnx(network, path): - inputs = [] - for i in range(network.num_inputs): - network_input = network.get_input(i) - inputs.append( - helper.make_tensor_value_info( - network_input.name, - trt_dtype_to_onnx(network_input.dtype), - list(network_input.shape), - ) - ) - - outputs = [] - for i in range(network.num_outputs): - network_output = network.get_output(i) - outputs.append( - helper.make_tensor_value_info( - network_output.name, - trt_dtype_to_onnx(network_output.dtype), - list(network_output.shape), - ) - ) - - nodes = [] - for i in range(network.num_layers): - layer = network.get_layer(i) - layer_inputs = [] - for j in range(layer.num_inputs): - ipt = layer.get_input(j) - if ipt is not None: - layer_inputs.append(layer.get_input(j).name) - layer_outputs = [layer.get_output(j).name for j in range(layer.num_outputs)] - nodes.append( - helper.make_node( - str(layer.type), - name=layer.name, - inputs=layer_inputs, - outputs=layer_outputs, - domain="com.nvidia", - ) - ) - - onnx_model = helper.make_model( - helper.make_graph(nodes, "attention", inputs, outputs, initializer=None), - producer_name="NVIDIA", - ) - onnx.save(onnx_model, path) - - -def get_engine_name(model, dtype, tp_size, pp_size, rank): - if pp_size == 1: - return "{}_{}_tp{}_rank{}.engine".format(model, dtype, tp_size, rank) - return "{}_{}_tp{}_pp{}_rank{}.engine".format(model, dtype, tp_size, pp_size, rank) - - -def serialize_engine(engine, path): - logger.info(f"Serializing engine to {path}...") - tik = time.time() - with open(path, "wb") as f: - f.write(bytearray(engine)) - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - logger.info(f"Engine serialized. Total time: {t}") - - -def parse_arguments(): - parser = argparse.ArgumentParser() - parser.add_argument("--world_size", type=int, default=1) - parser.add_argument("--tp_size", type=int, default=1) - parser.add_argument("--pp_size", type=int, default=1) - parser.add_argument("--model_dir", type=str, default=None) - parser.add_argument("--ft_model_dir", type=str, default=None) - parser.add_argument("--meta_ckpt_dir", type=str, default=None) - parser.add_argument("--quant_ckpt_path", type=str, default=None) - parser.add_argument( - "--dtype", - type=str, - default="float16", - choices=["float32", "bfloat16", "float16"], - ) - parser.add_argument( - "--timing_cache", - type=str, - default="model.cache", - help="The path of to read timing cache from, will be ignored if the file does not exist", - ) - parser.add_argument("--log_level", type=str, default="info") - parser.add_argument("--vocab_size", type=int, default=32000) - parser.add_argument("--n_layer", type=int, default=32) - parser.add_argument("--n_positions", type=int, default=2048) - parser.add_argument("--n_embd", type=int, default=4096) - parser.add_argument("--n_head", type=int, default=32) - parser.add_argument("--n_kv_head", type=int, default=None) - parser.add_argument("--multiple_of", type=int, default=256) - parser.add_argument("--ffn_dim_multiplier", type=float, default=1.0) - parser.add_argument("--inter_size", type=int, default=None) - parser.add_argument("--hidden_act", type=str, default="silu") - parser.add_argument("--rms_norm_eps", type=float, default=1e-06) - parser.add_argument("--max_batch_size", type=int, default=8) - parser.add_argument("--max_input_len", type=int, default=2048) - parser.add_argument("--max_output_len", type=int, default=512) - parser.add_argument("--max_beam_width", type=int, default=1) - parser.add_argument("--rotary_base", type=float, default=10000.0) - parser.add_argument("--rotary_scaling", nargs=2, type=str, default=None) - parser.add_argument( - "--use_gpt_attention_plugin", - nargs="?", - const="float16", - type=str, - default=False, - choices=["float16", "bfloat16", "float32"], - ) - parser.add_argument( - "--use_gemm_plugin", - nargs="?", - const="float16", - type=str, - default=False, - choices=["float16", "bfloat16", "float32"], - ) - parser.add_argument( - "--use_rmsnorm_plugin", - nargs="?", - const="float16", - type=str, - default=False, - choices=["float16", "float32", "bfloat16"], - ) - parser.add_argument("--parallel_build", default=False, action="store_true") - parser.add_argument("--enable_context_fmha", default=False, action="store_true") - parser.add_argument( - "--enable_context_fmha_fp32_acc", default=False, action="store_true" - ) - parser.add_argument("--visualize", default=False, action="store_true") - parser.add_argument("--enable_debug_output", default=False, action="store_true") - parser.add_argument("--gpus_per_node", type=int, default=8) - parser.add_argument("--builder_opt", type=int, default=None) - parser.add_argument( - "--output_dir", - type=str, - default="llama_outputs", - help="The path to save the serialized engine files, timing cache file and model configs", - ) - parser.add_argument("--remove_input_padding", default=False, action="store_true") - - # Arguments related to the quantization of the model. - parser.add_argument( - "--use_smooth_quant", - default=False, - action="store_true", - help="Use the SmoothQuant method to quantize activations and weights for the various GEMMs." - "See --per_channel and --per_token for finer-grained quantization options.", - ) - parser.add_argument( - "--per_channel", - default=False, - action="store_true", - help="By default, we use a single static scaling factor for the GEMM's result. " - "per_channel instead uses a different static scaling factor for each channel. " - "The latter is usually more accurate, but a little slower.", - ) - parser.add_argument( - "--per_token", - default=False, - action="store_true", - help="By default, we use a single static scaling factor to scale activations in the int8 range. " - "per_token chooses at run time, and for each token, a custom scaling factor. " - "The latter is usually more accurate, but a little slower.", - ) - parser.add_argument( - "--per_group", - default=False, - action="store_true", - help="By default, we use a single static scaling factor to scale weights in the int4 range. " - "per_group chooses at run time, and for each group, a custom scaling factor. " - "The flag is built for GPTQ/AWQ quantization.", - ) - parser.add_argument( - "--group_size", - type=int, - default=128, - help="Group size used in GPTQ/AWQ quantization.", - ) - parser.add_argument( - "--int8_kv_cache", - default=False, - action="store_true", - help="By default, we use dtype for KV cache. int8_kv_cache chooses int8 quantization for KV", - ) - parser.add_argument( - "--use_parallel_embedding", - action="store_true", - default=False, - help="By default embedding parallelism is disabled. By setting this flag, embedding parallelism is enabled", - ) - parser.add_argument( - "--embedding_sharding_dim", - type=int, - default=1, # Meta does TP on hidden dim - choices=[0, 1], - help="By default the embedding lookup table is sharded along vocab dimension (embedding_sharding_dim=0). " - "To shard it along hidden dimension, set embedding_sharding_dim=1" - "Note: embedding sharing is only enabled when embedding_sharding_dim = 0", - ) - parser.add_argument( - "--enable_fp8", - default=False, - action="store_true", - help="Use FP8 Linear layer for Attention QKV/Dense and MLP.", - ) - parser.add_argument( - "--fp8_kv_cache", - default=False, - action="store_true", - help="By default, we use dtype for KV cache. fp8_kv_cache chooses int8 quantization for KV", - ) - parser.add_argument( - "--quantized_fp8_model_path", - type=str, - default=None, - help="Path of a quantized model checkpoint in .npz format", - ) - parser.add_argument( - "--use_weight_only", - default=False, - action="store_true", - help="Quantize weights for the various GEMMs to INT4/INT8." - "See --weight_only_precision to set the precision", - ) - parser.add_argument( - "--weight_only_precision", - const="int8", - type=str, - nargs="?", - default="int8", - choices=["int8", "int4", "int4_awq", "int4_gptq"], - help="Define the precision for the weights when using weight-only quantization." - "You must also use --use_weight_only for that argument to have an impact.", - ) - parser.add_argument( - "--use_inflight_batching", - action="store_true", - default=False, - help="Activates inflight batching mode of gptAttentionPlugin.", - ) - parser.add_argument( - "--paged_kv_cache", - action="store_true", - default=False, - help="By default we use contiguous KV cache. By setting this flag you enable paged KV cache", - ) - parser.add_argument( - "--tokens_per_block", - type=int, - default=64, - help="Number of tokens per block in paged KV cache", - ) - parser.add_argument( - "--max_num_tokens", - type=int, - default=None, - help="Define the max number of tokens supported by the engine", - ) - parser.add_argument( - "--strongly_typed", - default=False, - action="store_true", - help="This option is introduced with trt 9.1.0.1+ and will reduce the building time significantly for fp8.", - ) - parser.add_argument( - "--use_custom_all_reduce", - action="store_true", - help="Activates latency-optimized algorithm for all-reduce instead of NCCL.", - ) - - args = parser.parse_args() - tensorrt_llm.logger.set_level(args.log_level) - - assert not ( - args.use_smooth_quant and args.use_weight_only - ), "You cannot enable both SmoothQuant and INT8 weight-only together." - - if not args.remove_input_padding: - if args.use_gpt_attention_plugin: - logger.warning( - f"It is recommended to specify --remove_input_padding when using GPT attention plugin" - ) - - if args.use_inflight_batching: - if not args.use_gpt_attention_plugin: - args.use_gpt_attention_plugin = "float16" - logger.info( - f"Using GPT attention plugin for inflight batching mode. Setting to default '{args.use_gpt_attention_plugin}'" - ) - if not args.remove_input_padding: - args.remove_input_padding = True - logger.info("Using remove input padding for inflight batching mode.") - if not args.paged_kv_cache: - args.paged_kv_cache = True - logger.info("Using paged KV cache for inflight batching mode.") - - if args.use_smooth_quant: - args.quant_mode = QuantMode.use_smooth_quant(args.per_token, args.per_channel) - elif args.use_weight_only: - if args.per_group: - args.quant_mode = QuantMode.from_description( - quantize_weights=True, - quantize_activations=False, - per_token=False, - per_channel=False, - per_group=True, - use_int4_weights=True, - ) - else: - args.quant_mode = QuantMode.use_weight_only( - args.weight_only_precision == "int4" - ) - else: - args.quant_mode = QuantMode(0) - - if args.int8_kv_cache: - args.quant_mode = args.quant_mode.set_int8_kv_cache() - elif args.fp8_kv_cache: - args.quant_mode = args.quant_mode.set_fp8_kv_cache() - if args.enable_fp8: - args.quant_mode = args.quant_mode.set_fp8_qdq() - - if args.rotary_scaling is not None: - rotary_scaling = { - "type": args.rotary_scaling[0], - "factor": float(args.rotary_scaling[1]), - } - assert rotary_scaling["type"] in ["linear", "dynamic"] - assert rotary_scaling["factor"] > 1.0 - args.rotary_scaling = rotary_scaling - if rotary_scaling["type"] == "dynamic": - assert not args.remove_input_padding, "TODO: Not supported yet" - - # Since gpt_attenttion_plugin is the only way to apply RoPE now, - # force use the plugin for now with the correct data type. - args.use_gpt_attention_plugin = args.dtype - if args.model_dir is not None: - hf_config = LlamaConfig.from_pretrained(args.model_dir) - args.inter_size = ( - hf_config.intermediate_size - ) # override the inter_size for LLaMA - args.n_embd = hf_config.hidden_size - args.n_head = hf_config.num_attention_heads - if hasattr(hf_config, "num_key_value_heads"): - args.n_kv_head = hf_config.num_key_value_heads - args.n_layer = hf_config.num_hidden_layers - args.n_positions = hf_config.max_position_embeddings - args.vocab_size = hf_config.vocab_size - args.hidden_act = hf_config.hidden_act - args.rms_norm_eps = hf_config.rms_norm_eps - elif args.meta_ckpt_dir is not None: - with open(Path(args.meta_ckpt_dir, "params.json")) as fp: - meta_config: dict = json.load(fp) - args.n_embd = meta_config["dim"] - args.n_head = meta_config["n_heads"] - args.n_layer = meta_config["n_layers"] - args.n_kv_head = meta_config.get("n_kv_heads", args.n_head) - args.multiple_of = meta_config["multiple_of"] - args.ffn_dim_multiplier = meta_config.get("ffn_dim_multiplier", 1) - n_embd = int(4 * args.n_embd * 2 / 3) - args.inter_size = args.multiple_of * ( - (int(n_embd * args.ffn_dim_multiplier) + args.multiple_of - 1) - // args.multiple_of - ) - args.rms_norm_eps = meta_config["norm_eps"] - elif args.ft_model_dir is not None: - ( - n_embd, - n_head, - n_layer, - n_positions, - vocab_size, - hidden_act, - inter_size, - n_kv_head, - ) = parse_ft_config(Path(args.ft_model_dir) / "config.ini") - args.inter_size = inter_size # override the inter_size for LLaMA - args.n_kv_head = n_kv_head - args.n_embd = n_embd - args.n_head = n_head - args.n_layer = n_layer - args.n_positions = n_positions - args.vocab_size = vocab_size - args.hidden_act = hidden_act - args.rms_norm_eps = 1e-06 - logger.warning("Set rms_norm_eps to 1e-06 directly.") - assert args.use_gpt_attention_plugin, "LLaMa must use gpt attention plugin" - if args.n_kv_head is None: - args.n_kv_head = args.n_head - elif args.n_kv_head != args.n_head: - assert ( - args.n_head % args.n_kv_head - ) == 0, "MQA/GQA requires the number of heads to be divisible by the number of K/V heads." - assert (args.n_kv_head % args.tp_size) == 0 or ( - args.tp_size % args.n_kv_head - ) == 0, ( - "MQA/GQA requires either the number of K/V heads to be divisible by the tensor parallelism size OR " - "the tensor parallelism size to be divisible by the number of K/V heads." - ) - - if args.dtype == "bfloat16": - assert args.use_gemm_plugin, "Please use gemm plugin when dtype is bfloat16" - - assert args.pp_size * args.tp_size == args.world_size - - if args.max_num_tokens is not None: - assert args.enable_context_fmha - - if args.inter_size is None: - # this should not be need when loading a real model - # but it is helpful when creating a dummy model without loading any real weights - n_embd = int(4 * args.n_embd * 2 / 3) - args.inter_size = args.multiple_of * ( - (int(n_embd * args.ffn_dim_multiplier) + args.multiple_of - 1) - // args.multiple_of - ) - logger.info(f"Setting inter_size to {args.inter_size}.") - - return args - - -def build_rank_engine( - builder: Builder, - builder_config: tensorrt_llm.builder.BuilderConfig, - engine_name, - rank, - args, -): - """ - @brief: Build the engine on the given rank. - @param rank: The rank to build the engine. - @param args: The cmd line arguments. - @return: The built engine. - """ - dtype = str_dtype_to_trt(args.dtype) - mapping = Mapping( - world_size=args.world_size, - rank=rank, - tp_size=args.tp_size, - pp_size=args.pp_size, - ) - - assert ( - args.n_layer % args.pp_size == 0 - ), f"num_layers {args.n_layer} must be a multiple of pipeline parallelism size {args.pp_size}" - - # Initialize Module - tensorrt_llm_llama = tensorrt_llm.models.LLaMAForCausalLM( - num_layers=args.n_layer, - num_heads=args.n_head, - num_kv_heads=args.n_kv_head, - hidden_size=args.n_embd, - vocab_size=args.vocab_size, - hidden_act=args.hidden_act, - max_position_embeddings=args.n_positions, - dtype=dtype, - mlp_hidden_size=args.inter_size, - position_embedding_type=PositionEmbeddingType.rope_gpt_neox, - mapping=mapping, - rotary_base=args.rotary_base, - rotary_scaling=args.rotary_scaling, - use_parallel_embedding=args.use_parallel_embedding, - embedding_sharding_dim=args.embedding_sharding_dim, - quant_mode=args.quant_mode, - rms_norm_eps=args.rms_norm_eps, - ) - if args.use_smooth_quant: - tensorrt_llm_llama = smooth_quantize(tensorrt_llm_llama, args.quant_mode) - elif args.use_weight_only: - if args.weight_only_precision == "int8": - tensorrt_llm_llama = weight_only_quantize( - tensorrt_llm_llama, args.quant_mode - ) - elif args.weight_only_precision == "int4": - tensorrt_llm_llama = weight_only_quantize( - tensorrt_llm_llama, args.quant_mode - ) - elif args.weight_only_precision == "int4_awq": - tensorrt_llm_llama = weight_only_groupwise_quantize( - model=tensorrt_llm_llama, - quant_mode=args.quant_mode, - group_size=args.group_size, - zero=False, - pre_quant_scale=True, - exclude_modules=[], - ) - elif args.weight_only_precision == "int4_gptq": - tensorrt_llm_llama = weight_only_groupwise_quantize( - model=tensorrt_llm_llama, - quant_mode=args.quant_mode, - group_size=args.group_size, - zero=True, - pre_quant_scale=False, - ) - elif args.enable_fp8 or args.fp8_kv_cache: - logger.info(f"Loading scaling factors from " f"{args.quantized_fp8_model_path}") - quant_scales = get_scaling_factors( - args.quantized_fp8_model_path, - num_layers=args.n_layer, - quant_mode=args.quant_mode, - ) - tensorrt_llm_llama = fp8_quantize( - tensorrt_llm_llama, quant_mode=args.quant_mode, quant_scales=quant_scales - ) - if args.per_group: - load_func = ( - load_from_awq_llama - if args.weight_only_precision == "int4_awq" - else load_from_gptq_llama - ) - load_func( - tensorrt_llm_llama=tensorrt_llm_llama, - quant_ckpt_path=args.quant_ckpt_path, - mapping=mapping, - dtype=args.dtype, - ) - elif args.meta_ckpt_dir is not None: - load_from_meta_llama( - tensorrt_llm_llama, args.meta_ckpt_dir, mapping, args.dtype - ) - elif args.model_dir is not None: - logger.info(f"Loading HF LLaMA ... from {args.model_dir}") - tik = time.time() - hf_llama = LlamaForCausalLM.from_pretrained( - args.model_dir, - device_map={"model": "cpu", "lm_head": "cpu"}, # Load to CPU memory - torch_dtype="auto", - ) - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - logger.info(f"HF LLaMA loaded. Total time: {t}") - load_from_hf_llama( - tensorrt_llm_llama, hf_llama, mapping=mapping, dtype=args.dtype - ) - del hf_llama - elif args.ft_model_dir is not None: - load_from_binary( - tensorrt_llm_llama, - args.ft_model_dir, - mapping, - fp16=(args.dtype == "float16"), - multi_query_mode=(args.n_kv_head != args.n_head), - ) - - # Module -> Network - network = builder.create_network() - network.trt_network.name = engine_name - if args.use_gpt_attention_plugin: - network.plugin_config.set_gpt_attention_plugin( - dtype=args.use_gpt_attention_plugin - ) - if args.use_gemm_plugin: - network.plugin_config.set_gemm_plugin(dtype=args.use_gemm_plugin) - if args.use_rmsnorm_plugin: - network.plugin_config.set_rmsnorm_plugin(dtype=args.use_rmsnorm_plugin) - - # Quantization plugins. - if args.use_smooth_quant: - network.plugin_config.set_smooth_quant_gemm_plugin(dtype=args.dtype) - network.plugin_config.set_rmsnorm_quantization_plugin(dtype=args.dtype) - network.plugin_config.set_quantize_tensor_plugin() - network.plugin_config.set_quantize_per_token_plugin() - assert not (args.enable_context_fmha and args.enable_context_fmha_fp32_acc) - if args.enable_context_fmha: - network.plugin_config.set_context_fmha(ContextFMHAType.enabled) - if args.enable_context_fmha_fp32_acc: - network.plugin_config.set_context_fmha(ContextFMHAType.enabled_with_fp32_acc) - if args.use_weight_only: - if args.per_group: - network.plugin_config.set_weight_only_groupwise_quant_matmul_plugin( - dtype="float16" - ) - else: - network.plugin_config.set_weight_only_quant_matmul_plugin(dtype="float16") - if args.world_size > 1: - network.plugin_config.set_nccl_plugin(args.dtype, args.use_custom_all_reduce) - if args.remove_input_padding: - network.plugin_config.enable_remove_input_padding() - if args.paged_kv_cache: - network.plugin_config.enable_paged_kv_cache(args.tokens_per_block) - - with net_guard(network): - # Prepare - network.set_named_parameters(tensorrt_llm_llama.named_parameters()) - - # Forward - inputs = tensorrt_llm_llama.prepare_inputs( - args.max_batch_size, - args.max_input_len, - args.max_output_len, - True, - args.max_beam_width, - args.max_num_tokens, - ) - tensorrt_llm_llama(*inputs) - if args.enable_debug_output: - # mark intermediate nodes' outputs - for k, v in tensorrt_llm_llama.named_network_outputs(): - v = v.trt_tensor - v.name = k - network.trt_network.mark_output(v) - v.dtype = dtype - if args.visualize: - model_path = os.path.join(args.output_dir, "test.onnx") - to_onnx(network.trt_network, model_path) - - tensorrt_llm.graph_rewriting.optimize(network) - - engine = None - - # Network -> Engine - engine = builder.build_engine(network, builder_config) - if rank == 0: - config_path = os.path.join(args.output_dir, "config.json") - builder.save_config(builder_config, config_path) - return engine - - -def build(rank, args): - torch.cuda.set_device(rank % args.gpus_per_node) - logger.set_level(args.log_level) - if not os.path.exists(args.output_dir): - os.makedirs(args.output_dir) - - # when doing serializing build, all ranks share one engine - builder = Builder() - - cache = None - for cur_rank in range(args.world_size): - # skip other ranks if parallel_build is enabled - if args.parallel_build and cur_rank != rank: - continue - # NOTE: when only int8 kv cache is used together with paged kv cache no int8 tensors are exposed to TRT - int8_trt_flag = args.quant_mode.has_act_and_weight_quant() or ( - not args.paged_kv_cache and args.quant_mode.has_int8_kv_cache() - ) - builder_config = builder.create_builder_config( - name=MODEL_NAME, - precision=args.dtype, - timing_cache=args.timing_cache if cache is None else cache, - tensor_parallel=args.tp_size, - pipeline_parallel=args.pp_size, - parallel_build=args.parallel_build, - num_layers=args.n_layer, - num_heads=args.n_head, - num_kv_heads=args.n_kv_head, - hidden_size=args.n_embd, - vocab_size=args.vocab_size, - hidden_act=args.hidden_act, - max_position_embeddings=args.n_positions, - max_batch_size=args.max_batch_size, - max_input_len=args.max_input_len, - max_output_len=args.max_output_len, - max_num_tokens=args.max_num_tokens, - int8=int8_trt_flag, - fp8=args.quant_mode.has_fp8_qdq(), - quant_mode=args.quant_mode, - strongly_typed=args.strongly_typed, - opt_level=args.builder_opt, - ) - engine_name = get_engine_name( - MODEL_NAME, args.dtype, args.tp_size, args.pp_size, cur_rank - ) - engine = build_rank_engine(builder, builder_config, engine_name, cur_rank, args) - assert engine is not None, f"Failed to build engine for rank {cur_rank}" - - if cur_rank == 0: - # Use in-memory timing cache for multiple builder passes. - if not args.parallel_build: - cache = builder_config.trt_builder_config.get_timing_cache() - - serialize_engine(engine, os.path.join(args.output_dir, engine_name)) - - if rank == 0: - ok = builder.save_timing_cache( - builder_config, os.path.join(args.output_dir, "model.cache") - ) - assert ok, "Failed to save timing cache." - - -if __name__ == "__main__": - args = parse_arguments() - tik = time.time() - if ( - args.parallel_build - and args.world_size > 1 - and torch.cuda.device_count() >= args.world_size - ): - logger.warning( - f"Parallelly build TensorRT engines. Please make sure that all of the {args.world_size} GPUs are totally free." - ) - mp.spawn(build, nprocs=args.world_size, args=(args,)) - else: - args.parallel_build = False - logger.info("Serially build TensorRT engines.") - build(0, args) - - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - logger.info(f"Total time of building all {args.world_size} engines: {t}") diff --git a/RetrievalAugmentedGeneration/llm-inference-server/conversion_scripts/llama/weight.py b/RetrievalAugmentedGeneration/llm-inference-server/conversion_scripts/llama/weight.py deleted file mode 100644 index 692ae67ff..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/conversion_scripts/llama/weight.py +++ /dev/null @@ -1,1446 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import configparser -import time -from operator import attrgetter -from pathlib import Path -from typing import Dict, List, Optional, Union - -import numpy as np -import tensorrt_llm -import tensorrt_llm.logger as logger -import torch -from safetensors import safe_open -from tensorrt_llm._utils import str_dtype_to_torch, torch_to_numpy -from tensorrt_llm.mapping import Mapping -from tensorrt_llm.models import LLaMAForCausalLM -from tensorrt_llm.models.quantized.quant import get_dummy_quant_scales -from tensorrt_llm.quantization import QuantMode - - -def get_scaling_factors( - model_path: Union[str, Path], - num_layers: int, - quant_mode: Optional[QuantMode] = None, -) -> Optional[Dict[str, List[int]]]: - """Get the scaling factors for LLaMA model - - Returns a dictionary of scaling factors for the selected layers of the - LLaMA model. - - Args: - model_path (str): Path to the quantized LLaMA model - layers (list): List of layers to get the scaling factors for. If None, - all layers are selected. - - Returns: - dict: Dictionary of scaling factors for the selected layers of the - LLaMA model. - - example: - - { - 'qkv_act': qkv_act_scale, - 'qkv_weights': qkv_weights_scale, - 'qkv_output' : qkv_outputs_scale, - 'dense_act': dense_act_scale, - 'dense_weights': dense_weights_scale, - 'fc_act': fc_act_scale, - 'fc_weights': fc_weights_scale, - 'gate_act': gate_act_scale, - 'gate_weights': gate_weights_scale, - 'proj_act': proj_act_scale, - 'proj_weights': proj_weights_scale, - } - """ - - if model_path is None: - logger.warning( - f"--quantized_fp8_model_path not specified. " - f"Initialize quantization scales automatically." - ) - return get_dummy_quant_scales(num_layers) - weight_dict = np.load(model_path) - - # yapf: disable - scaling_factor = { - 'qkv_act': [], - 'qkv_weights': [], - 'qkv_output': [], - 'dense_act': [], - 'dense_weights': [], - 'fc_act': [], - 'fc_weights': [], - 'gate_act': [], - 'gate_weights': [], - 'proj_act': [], - 'proj_weights': [], - } - - for layer in range(num_layers): - scaling_factor['qkv_act'].append(max( - weight_dict[f'_np:layers:{layer}:attention:qkv:q:activation_scaling_factor'].item(), - weight_dict[f'_np:layers:{layer}:attention:qkv:k:activation_scaling_factor'].item(), - weight_dict[f'_np:layers:{layer}:attention:qkv:v:activation_scaling_factor'].item() - )) - scaling_factor['qkv_weights'].append(max( - weight_dict[f'_np:layers:{layer}:attention:qkv:q:weights_scaling_factor'].item(), - weight_dict[f'_np:layers:{layer}:attention:qkv:k:weights_scaling_factor'].item(), - weight_dict[f'_np:layers:{layer}:attention:qkv:v:weights_scaling_factor'].item() - )) - if quant_mode is not None and quant_mode.has_fp8_kv_cache(): - # Not calibrarting KV cache. - scaling_factor['qkv_output'].append(1.0) - scaling_factor['dense_act'].append(weight_dict[f'_np:layers:{layer}:attention:dense:activation_scaling_factor'].item()) - scaling_factor['dense_weights'].append(weight_dict[f'_np:layers:{layer}:attention:dense:weights_scaling_factor'].item()) - scaling_factor['fc_act'].append(weight_dict[f'_np:layers:{layer}:mlp:fc:activation_scaling_factor'].item()) - scaling_factor['fc_weights'].append(weight_dict[f'_np:layers:{layer}:mlp:fc:weights_scaling_factor'].item()) - scaling_factor['gate_act'].append(weight_dict[f'_np:layers:{layer}:mlp:gate:activation_scaling_factor'].item()) - scaling_factor['gate_weights'].append(weight_dict[f'_np:layers:{layer}:mlp:gate:weights_scaling_factor'].item()) - scaling_factor['proj_act'].append(weight_dict[f'_np:layers:{layer}:mlp:proj:activation_scaling_factor'].item()) - scaling_factor['proj_weights'].append(weight_dict[f'_np:layers:{layer}:mlp:proj:weights_scaling_factor'].item()) - # yapf: enable - for k, v in scaling_factor.items(): - assert ( - len(v) == num_layers - ), f"Expect scaling factor {k} of length {num_layers}, got {len(v)}" - - return scaling_factor - - -def gen_suffix(rank, use_smooth_quant, quant_per_channel): - suffix = f"{rank}.bin" - if use_smooth_quant: - sq_prefix = "int8." - if quant_per_channel: - sq_prefix += "col." - suffix = sq_prefix + suffix - return suffix - - -def extract_layer_idx(name): - ss = name.split(".") - for s in ss: - if s.isdigit(): - return s - return None - - -def split(v, tp_size, idx, dim=0): - if tp_size == 1: - return v - if len(v.shape) == 1: - return np.ascontiguousarray(np.split(v, tp_size)[idx]) - else: - return np.ascontiguousarray(np.split(v, tp_size, axis=dim)[idx]) - - -def dup_kv_weight(v, num_head, tp_size): - assert tp_size % num_head == 0 - reps = tp_size // num_head - head_size = v.shape[0] // num_head - v = v.reshape(num_head, head_size, -1)[:, None, :, :].expand( - num_head, reps, head_size, v.shape[1] - ) - return v.reshape(num_head * reps * head_size, -1).clone() - - -def parse_ft_config(ini_file): - gpt_config = configparser.ConfigParser() - gpt_config.read(ini_file) - - n_embd = gpt_config.getint("llama", "hidden_size") - n_head = gpt_config.getint("llama", "num_attention_heads") - n_layer = gpt_config.getint("llama", "num_hidden_layers") - n_positions = gpt_config.getint("llama", "max_position_embeddings") - vocab_size = gpt_config.getint("llama", "vocab_size") - hidden_act = gpt_config.get("llama", "hidden_act") - inter_size = gpt_config.getint("llama", "intermediate_size", fallback=None) - n_kv_head = gpt_config.getint("llama", "num_key_value_heads", fallback=None) - - if inter_size is None: - inter_size = 4 * n_embd - - return ( - n_embd, - n_head, - n_layer, - n_positions, - vocab_size, - hidden_act, - inter_size, - n_kv_head, - ) - - -def load_from_hf_llama( - tensorrt_llm_llama: tensorrt_llm.models.LLaMAForCausalLM, - hf_llama, - mapping=Mapping(), - dtype="float32", -): - tensorrt_llm.logger.info("Loading weights from HF LLaMA...") - tik = time.time() - - quant_mode = getattr(tensorrt_llm_llama, "quant_mode", QuantMode(0)) - if quant_mode.is_int8_weight_only(): - plugin_weight_only_quant_type = torch.int8 - elif quant_mode.is_int4_weight_only(): - plugin_weight_only_quant_type = torch.quint4x2 - use_weight_only = quant_mode.is_weight_only() - num_kv_heads = tensorrt_llm_llama.num_kv_heads - mha_mode = num_kv_heads == tensorrt_llm_llama.num_heads - - model_params = dict(hf_llama.named_parameters()) - for l in range(hf_llama.config.num_hidden_layers): - prefix = f"model.layers.{l}.self_attn." - q_weight = model_params[prefix + "q_proj.weight"] - k_weight = model_params[prefix + "k_proj.weight"] - v_weight = model_params[prefix + "v_proj.weight"] - if not mha_mode: - head_size = tensorrt_llm_llama.hidden_size // tensorrt_llm_llama.num_heads - if num_kv_heads < mapping.tp_size: - # duplicate the KV heads up to tensor_parallel - k_weight = dup_kv_weight(k_weight, num_kv_heads, mapping.tp_size) - v_weight = dup_kv_weight(v_weight, num_kv_heads, mapping.tp_size) - assert (k_weight.shape[0] % (mapping.tp_size * head_size)) == 0 - assert (v_weight.shape[0] % (mapping.tp_size * head_size)) == 0 - qkv_weight = [q_weight, k_weight, v_weight] - else: - qkv_weight = torch.cat([q_weight, k_weight, v_weight], dim=0) - - model_params[prefix + "qkv_proj.weight"] = qkv_weight - - torch_dtype = str_dtype_to_torch(dtype) - layers_per_pipeline_stage = hf_llama.config.num_hidden_layers // mapping.pp_size - layers_range = list( - range( - mapping.pp_rank * layers_per_pipeline_stage, - (mapping.pp_rank + 1) * layers_per_pipeline_stage, - 1, - ) - ) - for k, v in model_params.items(): - if isinstance(v, list): - v = [torch_to_numpy(vv.to(torch_dtype).detach().cpu()) for vv in v] - else: - v = torch_to_numpy(v.to(torch_dtype).detach().cpu()) - if "model.embed_tokens.weight" in k: - if tensorrt_llm_llama.use_parallel_embedding: - v = split( - v, - mapping.tp_size, - mapping.tp_rank, - tensorrt_llm_llama.embedding_sharding_dim, - ) - if mapping.is_first_pp_rank(): - tensorrt_llm_llama.vocab_embedding.weight.value = v - elif "model.norm.weight" in k: - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.ln_f.weight.value = v - elif "lm_head.weight" in k: - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.lm_head.weight.value = np.ascontiguousarray( - split(v, mapping.tp_size, mapping.tp_rank) - ) - else: - layer_idx = extract_layer_idx(k) - if layer_idx is None or int(layer_idx) not in layers_range: - continue - idx = int(layer_idx) - mapping.pp_rank * layers_per_pipeline_stage - if idx >= tensorrt_llm_llama.num_layers: - continue - if "input_layernorm.weight" in k: - tensorrt_llm_llama.layers[idx].input_layernorm.weight.value = v - elif "post_attention_layernorm.weight" in k: - dst = tensorrt_llm_llama.layers[idx].post_layernorm.weight - dst.value = v - elif "self_attn.qkv_proj.weight" in k: - dst = tensorrt_llm_llama.layers[idx].attention.qkv.weight - if not mha_mode: - assert isinstance(v, list) and len(v) == 3 - wq = split(v[0], mapping.tp_size, mapping.tp_rank) - wk = split(v[1], mapping.tp_size, mapping.tp_rank) - wv = split(v[2], mapping.tp_size, mapping.tp_rank) - split_v = np.concatenate((wq, wk, wv)) - else: - q_emb = v.shape[0] // 3 - model_emb = v.shape[1] - v = v.reshape(3, q_emb, model_emb) - split_v = split(v, mapping.tp_size, mapping.tp_rank, dim=1) - split_v = split_v.reshape(3 * (q_emb // mapping.tp_size), model_emb) - if use_weight_only: - v = np.ascontiguousarray(split_v.transpose()) - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(v), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view( - dtype=torch.float32 - ).numpy() - scales = tensorrt_llm_llama.layers[ - idx - ].attention.qkv.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(split_v) - elif "self_attn.o_proj.weight" in k: - dst = tensorrt_llm_llama.layers[idx].attention.dense.weight - split_v = split(v, mapping.tp_size, mapping.tp_rank, dim=1) - if use_weight_only: - v = np.ascontiguousarray(split_v.transpose()) - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(v), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view( - dtype=torch.float32 - ).numpy() - scales = tensorrt_llm_llama.layers[ - idx - ].attention.dense.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(split_v) - elif "mlp.up_proj.weight" in k: - dst = tensorrt_llm_llama.layers[idx].mlp.gate.weight - split_v = split(v, mapping.tp_size, mapping.tp_rank, dim=0) - if use_weight_only: - v = np.ascontiguousarray(split_v.transpose()) - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(v), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view( - dtype=torch.float32 - ).numpy() - scales = tensorrt_llm_llama.layers[idx].mlp.gate.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(split_v) - elif "mlp.down_proj.weight" in k: - dst = tensorrt_llm_llama.layers[idx].mlp.proj.weight - split_v = split(v, mapping.tp_size, mapping.tp_rank, dim=1) - if use_weight_only: - v = np.ascontiguousarray(split_v.transpose()) - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(v), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view( - dtype=torch.float32 - ).numpy() - scales = tensorrt_llm_llama.layers[idx].mlp.proj.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(split_v) - elif "mlp.gate_proj.weight" in k: - dst = tensorrt_llm_llama.layers[idx].mlp.fc.weight - split_v = split(v, mapping.tp_size, mapping.tp_rank, dim=0) - if use_weight_only: - v = np.ascontiguousarray(split_v.transpose()) - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(v), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view( - dtype=torch.float32 - ).numpy() - scales = tensorrt_llm_llama.layers[idx].mlp.fc.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(split_v) - - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - tensorrt_llm.logger.info(f"Weights loaded. Total time: {t}") - return - - -def load_from_meta_llama( - tensorrt_llm_llama: tensorrt_llm.models.LLaMAForCausalLM, - meta_ckpt_dir, - mapping=Mapping(), - dtype="float32", -): - torch_dtype = str_dtype_to_torch(dtype) - - def gather_ckpts(ckpts): - gathered = {} - for k in ckpts[0]: - d = 0 - if any([n in k for n in ["wo", "w2", "tok"]]): - d = 1 - if "norm" in k or "rope" in k: # no TP - gathered[k] = ckpts[0][k].clone() - else: - gathered[k] = torch.cat([pt[k] for pt in ckpts], dim=d).clone() - return gathered - - def split_ckpt(ckpt, ranks_per_ckpt, ckpt_rank): - split_ckpt = {} - for k in ckpt: - d = 0 - if any([n in k for n in ["wo", "w2", "tok"]]): - d = 1 - if "norm" in k or "rope" in k: # no TP - split_ckpt[k] = ckpt[k].clone() - elif tensorrt_llm_llama.num_kv_heads < mapping.tp_size and any( - [n in k for n in ["wk", "wv"]] - ): - assert mapping.tp_size % tensorrt_llm_llama.num_kv_heads == 0 - # special case: we need to duplicate KV head - tmp = dup_kv_weight( - ckpt[k], tensorrt_llm_llama.num_kv_heads, mapping.tp_size - ) - split_ckpt[k] = torch.split(tmp, tmp.shape[d] // ranks_per_ckpt, dim=d)[ - ckpt_rank - ].clone() - else: - split_ckpt[k] = torch.split( - ckpt[k], ckpt[k].shape[d] // ranks_per_ckpt, dim=d - )[ckpt_rank].clone() - return split_ckpt - - def get_current_weights(num_ckpts): - if num_ckpts > mapping.tp_size: - # combine ckpts - assert (num_ckpts % mapping.tp_size) == 0 - nf = num_ckpts // mapping.tp_size - fs = nf * mapping.tp_rank - file_ids = list(range(fs, fs + nf)) - ckpts = [] - for f in file_ids: - ckpt = torch.load( - Path(meta_ckpt_dir, f"consolidated.{f:02d}.pth"), map_location="cpu" - ) - ckpts.append(ckpt) - return gather_ckpts(ckpts) - elif num_ckpts < mapping.tp_size: - # split ckpt - assert (mapping.tp_size % num_ckpts) == 0 - ranks_per_ckpt = mapping.tp_size // num_ckpts - ckpt_fid = mapping.tp_rank // ranks_per_ckpt - ckpt_rank = mapping.tp_rank % ranks_per_ckpt - nH_per_ckpt = tensorrt_llm_llama.num_heads // num_ckpts - assert (nH_per_ckpt % ranks_per_ckpt) == 0 - ckpt = torch.load( - Path(meta_ckpt_dir, f"consolidated.{ckpt_fid:02d}.pth"), - map_location="cpu", - ) - return split_ckpt(ckpt, ranks_per_ckpt, ckpt_rank) - - # num_ckpts == tensor_parallel, 1:1 mapping from files to TP - return torch.load( - Path(meta_ckpt_dir, f"consolidated.{mapping.tp_rank:02d}.pth"), - map_location="cpu", - ) - - def permute(w, nH, d, dH): - # due to MQA's wk, nH*dH != d could be true - return w.view(nH, dH // 2, 2, d).transpose(1, 2).reshape(nH * dH, d) - - if not hasattr(load_from_meta_llama, "saved_embed"): - load_from_meta_llama.saved_embed = None - - def gather_embedding(cur_embed, name: str, num_ckpts): - if mapping.tp_size == 1: - # even if num_ckpts > 1, get_current_weights will already have it gathered - return cur_embed - if load_from_meta_llama.saved_embed is None: - embeds = [None] * num_ckpts - for i in range(num_ckpts): - ckpt = torch.load( - Path(meta_ckpt_dir, f"consolidated.{i:02d}.pth"), map_location="cpu" - ) - embeds[i] = ckpt[name] - embed = torch.cat(embeds, dim=1).to(torch_dtype) - load_from_meta_llama.saved_embed = torch_to_numpy( - embed - ) # cache the embedding, not needed if no refit - return load_from_meta_llama.saved_embed - - tensorrt_llm.logger.info("Loading weights from Meta LLaMA checkpoints ...") - tik = time.time() - - quant_mode = getattr(tensorrt_llm_llama, "quant_mode", QuantMode(0)) - if quant_mode.is_int8_weight_only(): - torch.int8 - elif quant_mode.is_int4_weight_only(): - torch.quint4x2 - quant_mode.is_weight_only() - num_kv_heads = tensorrt_llm_llama.num_kv_heads - mha_mode = num_kv_heads == tensorrt_llm_llama.num_heads - - ckpts = list(Path(meta_ckpt_dir).glob("consolidated.*.pth")) - num_ckpts = len(ckpts) - # llama/llama2 doesn't have MQA. So, simplifying loader logic by not worrying about it. - assert ( - num_kv_heads > 1 or num_kv_heads >= num_ckpts - ), f"We don't know how the {num_kv_heads} KV heads are distributed among {num_ckpts} checkpoints." - - head_size = tensorrt_llm_llama.hidden_size // tensorrt_llm_llama.num_heads - ckpt = get_current_weights(num_ckpts) - layers_range = list( - range( - mapping.pp_rank * tensorrt_llm_llama.num_layers, - (mapping.pp_rank + 1) * tensorrt_llm_llama.num_layers, - 1, - ) - ) - - for l in layers_range: - prefix = f"layers.{l}.attention." - q_weight = permute( - ckpt[prefix + "wq.weight"].clone(), - nH=(tensorrt_llm_llama.num_heads // mapping.tp_size), - d=tensorrt_llm_llama.hidden_size, - dH=head_size, - ) - if num_kv_heads < mapping.tp_size and num_ckpts >= mapping.tp_size: - assert mapping.tp_size % num_kv_heads == 0 - assert False, "Not supported yet" - k_weight = permute( - ckpt[prefix + "wk.weight"].clone(), - nH=((num_kv_heads + mapping.tp_size - 1) // mapping.tp_size), - d=tensorrt_llm_llama.hidden_size, - dH=head_size, - ) - v_weight = ckpt[prefix + "wv.weight"].clone() - - qkv_weight = torch.cat([q_weight, k_weight, v_weight], dim=0) - ckpt[prefix + "qkv.weight"] = qkv_weight - - for k, v in ckpt.items(): - v = torch_to_numpy(v.to(torch_dtype).detach().cpu()) - if "tok_embeddings" in k: - if not tensorrt_llm_llama.use_parallel_embedding: - v = gather_embedding(v, k, num_ckpts) - elif tensorrt_llm_llama.embedding_sharding_dim == 0: - # this needs a gather and then resplit along different dims - v = gather_embedding(v, k, num_ckpts) - v = split(v, mapping.tp_size, mapping.tp_rank, 0) - if mapping.is_first_pp_rank(): - tensorrt_llm_llama.vocab_embedding.weight.value = v - elif "output" in k: - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.lm_head.weight.value = v - elif k == "norm.weight": - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.ln_f.weight.value = v - else: - # layer specific weights - layer_idx = extract_layer_idx(k) - if layer_idx is None: - continue - idx = int(layer_idx) - mapping.pp_rank * tensorrt_llm_llama.num_layers - if idx >= tensorrt_llm_llama.num_layers: - continue - if "attention_norm.weight" in k: - tensorrt_llm_llama.layers[idx].input_layernorm.weight.value = v - elif "ffn_norm.weight" in k: - tensorrt_llm_llama.layers[idx].post_layernorm.weight.value = v - elif "feed_forward.w3.weight" in k: - tensorrt_llm_llama.layers[idx].mlp.gate.weight.value = v - elif "feed_forward.w2.weight" in k: - tensorrt_llm_llama.layers[idx].mlp.proj.weight.value = v - elif "feed_forward.w1.weight" in k: - tensorrt_llm_llama.layers[idx].mlp.fc.weight.value = v - elif "attention.wo.weight" in k: - tensorrt_llm_llama.layers[idx].attention.dense.weight.value = v - elif "attention.qkv.weight" in k: - tensorrt_llm_llama.layers[idx].attention.qkv.weight.value = v - - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - tensorrt_llm.logger.info(f"Weights loaded. Total time: {t}") - return - - -def load_from_binary( - tensorrt_llm_llama: LLaMAForCausalLM, - dir_path, - mapping=Mapping(), - fp16=False, - multi_query_mode=False, -): - tensorrt_llm.logger.info("Loading weights from FT...") - tik = time.time() - - quant_mode = getattr(tensorrt_llm_llama, "quant_mode", QuantMode(0)) - - ( - n_embd, - n_head, - n_layer, - n_positions, - vocab_size, - hidden_act, - inter_size, - n_kv_head, - ) = parse_ft_config(Path(dir_path) / "config.ini") - np_dtype = np.float16 if fp16 else np.float32 - - def fromfile(dir_path, name, shape=None, dtype=None): - dtype = np_dtype if dtype is None else dtype - p = dir_path + "/" + name - if Path(p).exists(): - t = np.fromfile(p, dtype=dtype) - if shape is not None: - t = t.reshape(shape) - return t - return None - - def set_smoothquant_scale_factors( - module, - pre_scale_weight, - dir_path, - basename, - shape, - per_tok_dyn, - per_channel, - is_qkv=False, - rank=None, - ): - suffix = "bin" - if per_channel: - if rank is not None: - suffix = f"{rank}." + suffix - suffix = "col." + suffix - - col_shape = shape if (per_channel or is_qkv) else [1, 1] - - if per_tok_dyn: - if pre_scale_weight is not None: - pre_scale_weight.value = np.array([1.0], dtype=np.float32) - if is_qkv and not per_channel: - t = fromfile( - dir_path, - f"{basename}scale_w_quant_orig.{rank}.{suffix}", - col_shape, - np.float32, - ) - else: - t = fromfile( - dir_path, - f"{basename}scale_w_quant_orig.{suffix}", - col_shape, - np.float32, - ) - module.per_channel_scale.value = t - else: - t = fromfile(dir_path, f"{basename}scale_x_orig_quant.bin", [1], np.float32) - pre_scale_weight.value = t - if is_qkv: - t = fromfile( - dir_path, - f"{basename}scale_y_accum_quant.{rank}.{suffix}", - col_shape, - np.float32, - ) - else: - t = fromfile( - dir_path, - f"{basename}scale_y_accum_quant.{suffix}", - col_shape, - np.float32, - ) - module.per_channel_scale.value = t - t = fromfile( - dir_path, f"{basename}scale_y_quant_orig.bin", [1, 1], np.float32 - ) - module.act_scale.value = t - - def set_smoother(module, dir_path, base_name, shape, rank): - suffix = f"{rank}.bin" - t = fromfile(dir_path, f"{base_name}.smoother.{suffix}", shape, np.float32) - module.smoother.value = t - - # Determine the quantization mode. - quant_mode = getattr(tensorrt_llm_llama, "quant_mode", QuantMode(0)) - if quant_mode.is_int8_weight_only(): - plugin_weight_only_quant_type = torch.int8 - elif quant_mode.is_int4_weight_only(): - plugin_weight_only_quant_type = torch.quint4x2 - # Do we use SmoothQuant? - use_smooth_quant = quant_mode.has_act_and_weight_quant() - # Do we use quantization per token? - quant_per_token_dyn = quant_mode.has_per_token_dynamic_scaling() - # Do we use quantization per channel? - quant_per_channel = quant_mode.has_per_channel_scaling() - - # Do we use INT4/INT8 weight-only? - use_weight_only = quant_mode.is_weight_only() - - # Int8 KV cache - use_int8_kv_cache = quant_mode.has_int8_kv_cache() - - def sq_trick(x): - return x.view(np.float32) if use_smooth_quant else x - - # Debug - suffix = gen_suffix(mapping.tp_rank, use_smooth_quant, quant_per_channel) - # The type of weights. - w_type = np_dtype if not use_smooth_quant else np.int8 - - if mapping.is_first_pp_rank(): - tensorrt_llm_llama.vocab_embedding.weight.value = fromfile( - dir_path, "vocab_embedding.weight.bin", [vocab_size, n_embd] - ) - - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.ln_f.weight.value = fromfile(dir_path, "ln_f.weight.bin") - # share input embedding - lm_head_weight = fromfile(dir_path, "lm_head.weight.bin", [vocab_size, n_embd]) - - if vocab_size % mapping.tp_size != 0: - # padding - vocab_size_padded = tensorrt_llm_llama.lm_head.out_features * mapping.tp_size - pad_width = vocab_size_padded - vocab_size - lm_head_weight = np.pad( - lm_head_weight, ((0, pad_width), (0, 0)), "constant", constant_values=0 - ) - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.lm_head.weight.value = np.ascontiguousarray( - split(lm_head_weight, mapping.tp_size, mapping.tp_rank) - ) - - layers_range = list( - range( - mapping.pp_rank * tensorrt_llm_llama.num_layers, - (mapping.pp_rank + 1) * tensorrt_llm_llama.num_layers, - 1, - ) - ) - - for i in layers_range: - n_groups = n_head // n_kv_head - c_attn_out_dim = ( - (3 * n_embd // mapping.tp_size) - if not multi_query_mode - else ( - n_embd // mapping.tp_size - + (n_embd // n_head * n_groups) // mapping.tp_size * 2 - ) - ) - idx = i - mapping.pp_rank * tensorrt_llm_llama.num_layers - tensorrt_llm_llama.layers[idx].input_layernorm.weight.value = fromfile( - dir_path, "model.layers." + str(i) + ".input_layernorm.weight.bin" - ) - t = fromfile( - dir_path, - "model.layers." + str(i) + ".attention.query_key_value.weight." + suffix, - [n_embd, c_attn_out_dim], - w_type, - ) - if t is not None: - dst = tensorrt_llm_llama.layers[idx].attention.qkv.weight - if use_smooth_quant: - dst.value = sq_trick(np.ascontiguousarray(np.transpose(t, [1, 0]))) - set_smoothquant_scale_factors( - tensorrt_llm_llama.layers[idx].attention.qkv, - tensorrt_llm_llama.layers[idx].input_layernorm.scale_to_int, - dir_path, - "model.layers." + str(i) + ".attention.query_key_value.", - [1, c_attn_out_dim], - quant_per_token_dyn, - quant_per_channel, - rank=mapping.tp_rank, - is_qkv=True, - ) - elif use_weight_only: - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(t), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view(dtype=torch.float32).numpy() - scales = tensorrt_llm_llama.layers[i].attention.qkv.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(np.transpose(t, [1, 0])) - - dst = tensorrt_llm_llama.layers[idx].attention.dense.weight - t = fromfile( - dir_path, - "model.layers." + str(i) + ".attention.dense.weight." + suffix, - [n_embd // mapping.tp_size, n_embd], - w_type, - ) - if use_smooth_quant: - dst.value = sq_trick(np.ascontiguousarray(np.transpose(t, [1, 0]))) - dense_scale = getattr( - tensorrt_llm_llama.layers[idx].attention, - "quantization_scaling_factor", - None, - ) - set_smoothquant_scale_factors( - tensorrt_llm_llama.layers[idx].attention.dense, - dense_scale, - dir_path, - "model.layers." + str(i) + ".attention.dense.", - [1, n_embd], - quant_per_token_dyn, - quant_per_channel, - ) - set_smoother( - tensorrt_llm_llama.layers[idx].attention.dense, - dir_path, - "model.layers." + str(i) + ".attention.dense", - [1, n_embd // mapping.tp_size], - mapping.tp_rank, - ) - elif use_weight_only: - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(t), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view(dtype=torch.float32).numpy() - scales = tensorrt_llm_llama.layers[i].attention.dense.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - dst.value = np.ascontiguousarray(np.transpose(t, [1, 0])) - - dst = tensorrt_llm_llama.layers[idx].post_layernorm.weight - dst.value = fromfile( - dir_path, "model.layers." + str(i) + ".post_layernorm.weight.bin" - ) - - t = fromfile( - dir_path, - "model.layers." + str(i) + ".mlp.fc.weight." + suffix, - [n_embd, inter_size // mapping.tp_size], - w_type, - ) - - if use_smooth_quant: - tensorrt_llm_llama.layers[idx].mlp.fc.weight.value = sq_trick( - np.ascontiguousarray(np.transpose(t, [1, 0])) - ) - set_smoothquant_scale_factors( - tensorrt_llm_llama.layers[idx].mlp.fc, - tensorrt_llm_llama.layers[idx].post_layernorm.scale_to_int, - dir_path, - "model.layers." + str(i) + ".mlp.fc.", - [1, inter_size // mapping.tp_size], - quant_per_token_dyn, - quant_per_channel, - rank=mapping.tp_rank, - ) - elif use_weight_only: - dst = tensorrt_llm_llama.layers[i].mlp.fc.weight - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(t), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view(dtype=torch.float32).numpy() - scales = tensorrt_llm_llama.layers[i].mlp.fc.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - tensorrt_llm_llama.layers[idx].mlp.fc.weight.value = np.ascontiguousarray( - np.transpose(t, [1, 0]) - ) - - t = fromfile( - dir_path, - "model.layers." + str(i) + ".mlp.gate.weight." + suffix, - [n_embd, inter_size // mapping.tp_size], - w_type, - ) - if use_smooth_quant: - tensorrt_llm_llama.layers[idx].mlp.gate.weight.value = sq_trick( - np.ascontiguousarray(np.transpose(t, [1, 0])) - ) - set_smoothquant_scale_factors( - tensorrt_llm_llama.layers[idx].mlp.gate, - tensorrt_llm_llama.layers[idx].post_layernorm.scale_to_int, - dir_path, - "model.layers." + str(i) + ".mlp.gate.", - [1, inter_size // mapping.tp_size], - quant_per_token_dyn, - quant_per_channel, - rank=mapping.tp_rank, - ) - elif use_weight_only: - dst = tensorrt_llm_llama.layers[i].mlp.gate.weight - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(t), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view(dtype=torch.float32).numpy() - scales = tensorrt_llm_llama.layers[i].mlp.gate.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - tensorrt_llm_llama.layers[idx].mlp.gate.weight.value = np.ascontiguousarray( - np.transpose(t, [1, 0]) - ) - - t = fromfile( - dir_path, - "model.layers." + str(i) + ".mlp.proj.weight." + suffix, - [inter_size // mapping.tp_size, n_embd], - w_type, - ) - if use_smooth_quant: - tensorrt_llm_llama.layers[idx].mlp.proj.weight.value = sq_trick( - np.ascontiguousarray(np.transpose(t, [1, 0])) - ) - proj_scale = getattr( - tensorrt_llm_llama.layers[idx].mlp, "quantization_scaling_factor", None - ) - set_smoothquant_scale_factors( - tensorrt_llm_llama.layers[idx].mlp.proj, - proj_scale, - dir_path, - "model.layers." + str(i) + ".mlp.proj.", - [1, n_embd], - quant_per_token_dyn, - quant_per_channel, - ) - set_smoother( - tensorrt_llm_llama.layers[idx].mlp.proj, - dir_path, - "model.layers." + str(i) + ".mlp.proj", - [1, inter_size // mapping.tp_size], - mapping.tp_rank, - ) - elif use_weight_only: - dst = tensorrt_llm_llama.layers[i].mlp.proj.weight - ( - processed_torch_weights, - torch_weight_scales, - ) = torch.ops.fastertransformer.symmetric_quantize_last_axis_of_batched_matrix( - torch.tensor(t), plugin_weight_only_quant_type - ) - # workaround for trt not supporting int8 inputs in plugins currently - dst.value = processed_torch_weights.view(dtype=torch.float32).numpy() - scales = tensorrt_llm_llama.layers[i].mlp.proj.per_channel_scale - scales.value = torch_weight_scales.numpy() - else: - tensorrt_llm_llama.layers[idx].mlp.proj.weight.value = np.ascontiguousarray( - np.transpose(t, [1, 0]) - ) - - if use_int8_kv_cache: - t = fromfile( - dir_path, - "model.layers." - + str(i) - + ".attention.query_key_value.scale_y_quant_orig.bin", - [1], - np.float32, - ) - tensorrt_llm_llama.layers[idx].attention.kv_orig_quant_scale.value = 1.0 / t - tensorrt_llm_llama.layers[idx].attention.kv_quant_orig_scale.value = t - - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - tensorrt_llm.logger.info(f"Weights loaded. Total time: {t}") - - -def load_from_gptq_llama( - tensorrt_llm_llama, quant_ckpt_path, mapping=Mapping(), dtype="float16" -): - tensorrt_llm.logger.info("Loading weights from groupwise GPTQ LLaMA safetensors...") - tik = time.time() - - if quant_ckpt_path.endswith(".safetensors"): - groupwise_qweight_safetensors = safe_open( - quant_ckpt_path, framework="pt", device=0 - ) - model_params = { - key: groupwise_qweight_safetensors.get_tensor(key) - for key in groupwise_qweight_safetensors.keys() - } - elif quant_ckpt_path.endswith(".pt"): - model_params = torch.load(quant_ckpt_path, map_location=torch.device("cpu")) - else: - assert False, "Quantized checkpoint format not supported!" - - def unpack_int32_into_int8(w_packed): - # Unpack inputs packed in int32/float32 into uint4 and store them in int8 format - w_packed_int4x2 = w_packed.contiguous().view(torch.uint8) - w_unpacked = torch.zeros( - w_packed_int4x2.shape[0], w_packed_int4x2.shape[1] * 2, dtype=torch.int8 - ) - w_unpacked[:, ::2] = w_packed_int4x2 % 16 - w_unpacked[:, 1::2] = w_packed_int4x2 // 16 - return w_unpacked.contiguous() - - def preprocess_groupwise_weight_params( - weight_name, qweight_int32=None, qzeros_int32=None, scales_fp16=None - ): - if weight_name is not None: - qweight_int32 = model_params[weight_name].cpu() - qzeros_int32 = model_params[weight_name[:-7] + "qzeros"].cpu() - scales_fp16 = model_params[weight_name[:-7] + "scales"].cpu() - - UINT4_TO_INT4_FLAG = 1 - GPTQ_FLAG = 1 - packer = torch.ops.fastertransformer.pack_int8_tensor_to_packed_int4 - preprocessor = torch.ops.fastertransformer.preprocess_weights_for_mixed_gemm - - qweight_unpacked_int8 = ( - unpack_int32_into_int8(qweight_int32.T).T.contiguous() - 8 - ) - qweight_interleaved = preprocessor( - packer(qweight_unpacked_int8), torch.quint4x2 - ).view(torch.float32) - # zeros = zeros * scales - qzeros_unpacked_int32 = unpack_int32_into_int8(qzeros_int32) - zeros_x_scales_fp16 = ( - -qzeros_unpacked_int32 + 8 * UINT4_TO_INT4_FLAG - GPTQ_FLAG - ) * scales_fp16 - zeros_x_scales_fp16 = zeros_x_scales_fp16.half() - - # return processed interleaved weight, original scales and zeros * scales - return ( - qweight_interleaved.contiguous(), - scales_fp16.contiguous(), - zeros_x_scales_fp16.contiguous(), - ) - - layer_ids = [extract_layer_idx(key) for key in groupwise_qweight_safetensors.keys()] - layer_ids = [int(layer_idx) for layer_idx in layer_ids if layer_idx is not None] - num_hidden_layers = max(layer_ids) + 1 - num_kv_heads = tensorrt_llm_llama.num_kv_heads - mha_mode = num_kv_heads == tensorrt_llm_llama.num_heads - suffixs = ["qweight", "qzeros", "scales"] - - layers_per_pipeline_stage = num_hidden_layers // mapping.pp_size - layers_range = list( - range( - mapping.pp_rank * layers_per_pipeline_stage, - (mapping.pp_rank + 1) * layers_per_pipeline_stage, - 1, - ) - ) - - for l in layers_range: - prefix = f"model.layers.{l}.self_attn." - split_qkv_suf = [] - - for suf in suffixs: - q_part = model_params[prefix + "q_proj." + suf].cpu() - k_part = model_params[prefix + "k_proj." + suf].cpu() - v_part = model_params[prefix + "v_proj." + suf].cpu() - qkv_part = torch.cat([q_part, k_part, v_part], dim=0) - dim = qkv_part.shape - qkv_part = qkv_part.reshape(3, dim[0] // 3, dim[1]) - split_qkv = qkv_part.split(dim[1] // mapping.tp_size, dim=2)[ - mapping.tp_rank - ] - split_qkv = torch.cat( - [ - split_qkv[0, :, :].squeeze(0), - split_qkv[1, :, :].squeeze(0), - split_qkv[2, :, :].squeeze(0), - ], - dim=1, - ) - split_qkv_suf.append(split_qkv) - - th_qweight, th_zero, th_scale = preprocess_groupwise_weight_params( - None, split_qkv_suf[0], split_qkv_suf[1], split_qkv_suf[2] - ) - - idx = l - mapping.pp_rank * layers_per_pipeline_stage - tensorrt_llm_llama.layers[idx].attention.qkv.qweight.value = th_qweight.numpy() - tensorrt_llm_llama.layers[idx].attention.qkv.scale.value = th_zero.numpy() - tensorrt_llm_llama.layers[idx].attention.qkv.zero.value = th_scale.numpy() - - torch_dtype = str_dtype_to_torch(dtype) - - for k, v in model_params.items(): - if isinstance(v, list): - v = [torch_to_numpy(vv.to(torch_dtype).detach().cpu()) for vv in v] - else: - v = torch_to_numpy(v.to(torch_dtype).detach().cpu()) - if "model.embed_tokens.weight" in k: - if mapping.is_first_pp_rank(): - tensorrt_llm_llama.vocab_embedding.weight.value = v - elif "model.norm.weight" in k: - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.ln_f.weight.value = v - elif "lm_head.weight" in k: - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.lm_head.weight.value = np.ascontiguousarray( - split(v, mapping.tp_size, mapping.tp_rank) - ) - else: - layer_idx = extract_layer_idx(k) - if layer_idx is None: - continue - idx = int(layer_idx) - if idx not in layers_range: - continue - idx = idx - mapping.pp_rank * layers_per_pipeline_stage - - if "input_layernorm.weight" in k: - tensorrt_llm_llama.layers[idx].input_layernorm.weight.value = v - elif "post_attention_layernorm.weight" in k: - tensorrt_llm_llama.layers[idx].post_layernorm.weight.value = v - elif "self_attn.o_proj.qweight" in k: - split_v_suf = [] - for suf in suffixs: - v = model_params[k[:-7] + suf].cpu() - split_v = v.split(v.shape[0] // mapping.tp_size, dim=0)[ - mapping.tp_rank - ] - split_v_suf.append(split_v) - th_qweight, th_zero, th_scale = preprocess_groupwise_weight_params( - None, split_v_suf[0], split_v_suf[1], split_v_suf[2] - ) - tensorrt_llm_llama.layers[ - idx - ].attention.dense.qweight.value = th_qweight.numpy() - tensorrt_llm_llama.layers[ - idx - ].attention.dense.scale.value = th_zero.numpy() - tensorrt_llm_llama.layers[ - idx - ].attention.dense.zero.value = th_scale.numpy() - elif "mlp.up_proj.qweight" in k: - split_v_suf = [] - for suf in suffixs: - v = model_params[k[:-7] + suf].cpu() - split_v = v.split(v.shape[1] // mapping.tp_size, dim=1)[ - mapping.tp_rank - ] - split_v_suf.append(split_v) - th_qweight, th_zero, th_scale = preprocess_groupwise_weight_params( - None, split_v_suf[0], split_v_suf[1], split_v_suf[2] - ) - tensorrt_llm_llama.layers[ - idx - ].mlp.gate.qweight.value = th_qweight.numpy() - tensorrt_llm_llama.layers[idx].mlp.gate.scale.value = th_zero.numpy() - tensorrt_llm_llama.layers[idx].mlp.gate.zero.value = th_scale.numpy() - elif "mlp.down_proj.qweight" in k: - split_v_suf = [] - for suf in suffixs: - v = model_params[k[:-7] + suf].cpu() - split_v = v.split(v.shape[0] // mapping.tp_size, dim=0)[ - mapping.tp_rank - ] - split_v_suf.append(split_v) - th_qweight, th_zero, th_scale = preprocess_groupwise_weight_params( - None, split_v_suf[0], split_v_suf[1], split_v_suf[2] - ) - tensorrt_llm_llama.layers[ - idx - ].mlp.proj.qweight.value = th_qweight.numpy() - tensorrt_llm_llama.layers[idx].mlp.proj.scale.value = th_zero.numpy() - tensorrt_llm_llama.layers[idx].mlp.proj.zero.value = th_scale.numpy() - elif "mlp.gate_proj.qweight" in k: - split_v_suf = [] - for suf in suffixs: - v = model_params[k[:-7] + suf].cpu() - split_v = v.split(v.shape[1] // mapping.tp_size, dim=1)[ - mapping.tp_rank - ] - split_v_suf.append(split_v) - th_qweight, th_zero, th_scale = preprocess_groupwise_weight_params( - None, split_v_suf[0], split_v_suf[1], split_v_suf[2] - ) - tensorrt_llm_llama.layers[idx].mlp.fc.qweight.value = th_qweight.numpy() - tensorrt_llm_llama.layers[idx].mlp.fc.scale.value = th_zero.numpy() - tensorrt_llm_llama.layers[idx].mlp.fc.zero.value = th_scale.numpy() - - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - tensorrt_llm.logger.info(f"Weights loaded. Total time: {t}") - return - - -def load_from_awq_llama( - tensorrt_llm_llama: LLaMAForCausalLM, - quant_ckpt_path, - mapping=Mapping(), - dtype="float16", -): - tensorrt_llm.logger.info("Loading weights from groupwise AWQ LLaMA safetensors...") - tik = time.time() - - if quant_ckpt_path.endswith(".safetensors"): - groupwise_qweight_safetensors = safe_open( - quant_ckpt_path, framework="pt", device=0 - ) - awq_llama = { - key: groupwise_qweight_safetensors.get_tensor(key) - for key in groupwise_qweight_safetensors.keys() - } - elif quant_ckpt_path.endswith(".pt"): - awq_llama = torch.load(quant_ckpt_path, map_location=torch.device("cpu")) - else: - assert False, "Quantized checkpoint format not supported!" - - group_size = ( - awq_llama["model.layers.0.self_attn.o_proj.weight"].numel() - // awq_llama["model.layers.0.self_attn.o_proj.weight_quantizer._amax"].numel() - ) - - awq_llama_block_names = [ - "input_layernorm.weight", - "post_attention_layernorm.weight", - ] - - tensorrt_llm_llama_block_names = [ - "input_layernorm.weight", - "post_layernorm.weight", - ] - - getattr(tensorrt_llm_llama, "quant_mode", QuantMode(0)) - - packer = torch.ops.fastertransformer.pack_int8_tensor_to_packed_int4 - preprocessor = torch.ops.fastertransformer.preprocess_weights_for_mixed_gemm - torch_dtype = str_dtype_to_torch(dtype) - - def AWQ_quantize_pack_preprocess(weight, scale): - scale = scale.repeat_interleave(group_size, dim=0) - weight = weight / scale - qweight_int8 = torch.clamp(torch.round(weight.cuda()).char(), -8, 7) - int4_weight = packer(qweight_int8.cpu()) - int4_weight = preprocessor(int4_weight, torch.quint4x2) - return int4_weight.view(torch.float32).cpu().numpy() - - def process_and_assign_weight(awq_llama, mPrefix, mOp, tp_dim=0): - weight = awq_llama[mPrefix + ".weight"].T.contiguous() - [k, n] = weight.shape - weight = weight.split(weight.shape[tp_dim] // mapping.tp_size, dim=tp_dim)[ - mapping.tp_rank - ] - amax = ( - awq_llama[mPrefix + ".weight_quantizer._amax"] - .reshape((n, int(k / group_size))) - .T.contiguous() - ) - amax = amax.split(amax.shape[tp_dim] // mapping.tp_size, dim=tp_dim)[ - mapping.tp_rank - ] - pre_quant_scale = awq_llama[ - mPrefix + ".input_quantizer._pre_quant_scale" - ].reshape((1, k)) - if tp_dim == 0: - pre_quant_scale = pre_quant_scale.split(k // mapping.tp_size, dim=1)[ - mapping.tp_rank - ] - scale = amax / 8.0 - mOp.qweight.value = AWQ_quantize_pack_preprocess(weight, scale) - mOp.scale.value = scale.to(torch_dtype).cpu().numpy() - mOp.pre_quant_scale.value = pre_quant_scale.to(torch_dtype).cpu().numpy() - - def deSmooth(weight, pre_quant_scale): - [k, n] = weight.shape - pre_quant_scale = pre_quant_scale.repeat((n, 1)).transpose(1, 0).contiguous() - weight = weight * pre_quant_scale - return weight - - def reSmooth(weight, pre_quant_scale): - [k, n] = weight.shape - pre_quant_scale = pre_quant_scale.repeat((n, 1)).transpose(1, 0).contiguous() - weight = weight / pre_quant_scale - return weight - - def get_scale(weight): - weight = weight.T.contiguous() - [n, k] = weight.shape - weight = weight.reshape(n, int(k / group_size), group_size) - weight = torch.abs(weight.reshape(-1, group_size)) - amax, idx = weight.max(1) - amax = amax.reshape(n, int(k / group_size)).T.contiguous() - return amax / 8 - - def reSmooth_and_get_scale(weight, pre_quant_scale, avg_pre_quant_scale): - weight = deSmooth(weight, pre_quant_scale) - weight = reSmooth(weight, avg_pre_quant_scale) - scale = get_scale(weight) - return weight, scale - - def process_and_assign_qkv_weight(awq_llama, prefix, mOp): - q_weight = awq_llama[prefix + "self_attn.q_proj.weight"].T.contiguous() - k_weight = awq_llama[prefix + "self_attn.k_proj.weight"].T.contiguous() - v_weight = awq_llama[prefix + "self_attn.v_proj.weight"].T.contiguous() - k = q_weight.shape[0] - - q_weight = q_weight.split(q_weight.shape[1] // mapping.tp_size, dim=1)[ - mapping.tp_rank - ] - k_weight = k_weight.split(k_weight.shape[1] // mapping.tp_size, dim=1)[ - mapping.tp_rank - ] - v_weight = v_weight.split(v_weight.shape[1] // mapping.tp_size, dim=1)[ - mapping.tp_rank - ] - - q_pre_quant_scale = awq_llama[ - prefix + "self_attn.q_proj.input_quantizer._pre_quant_scale" - ].reshape((1, k)) - k_pre_quant_scale = awq_llama[ - prefix + "self_attn.k_proj.input_quantizer._pre_quant_scale" - ].reshape((1, k)) - v_pre_quant_scale = awq_llama[ - prefix + "self_attn.v_proj.input_quantizer._pre_quant_scale" - ].reshape((1, k)) - - qkv_pre_quant_scale = ( - q_pre_quant_scale + k_pre_quant_scale + v_pre_quant_scale - ) / 3.0 - q_weight, q_scale = reSmooth_and_get_scale( - q_weight, q_pre_quant_scale, qkv_pre_quant_scale - ) - k_weight, k_scale = reSmooth_and_get_scale( - k_weight, k_pre_quant_scale, qkv_pre_quant_scale - ) - v_weight, v_scale = reSmooth_and_get_scale( - v_weight, v_pre_quant_scale, qkv_pre_quant_scale - ) - - qkv_weights = torch.cat((q_weight, k_weight, v_weight), dim=1) - qkv_scale = torch.cat((q_scale, k_scale, v_scale), dim=1) - - mOp.pre_quant_scale.value = qkv_pre_quant_scale.to(torch_dtype).cpu().numpy() - mOp.qweight.value = AWQ_quantize_pack_preprocess(qkv_weights, qkv_scale) - mOp.scale.value = qkv_scale.to(torch_dtype).cpu().numpy() - - # Check if we need to pad vocab - v = awq_llama.get("model.embed_tokens.weight") - [vocab_size, k] = v.shape - pad_vocab = False - pad_vocab_size = vocab_size - if vocab_size % 64 != 0: - pad_vocab = True - pad_vocab_size = int((vocab_size + 63) / 64) * 64 - if pad_vocab: - new_v = torch.zeros([pad_vocab_size, k]) - new_v[:vocab_size, :] = v - v = new_v - if mapping.is_first_pp_rank(): - tensorrt_llm_llama.vocab_embedding.weight.value = ( - v.to(torch_dtype).cpu().numpy() - ) - - layer_ids = [extract_layer_idx(key) for key in awq_llama.keys()] - layer_ids = [int(layer_idx) for layer_idx in layer_ids if layer_idx is not None] - - num_hidden_layers = max(layer_ids) + 1 - layers_per_pipeline_stage = num_hidden_layers // mapping.pp_size - layers_range = list( - range( - mapping.pp_rank * layers_per_pipeline_stage, - (mapping.pp_rank + 1) * layers_per_pipeline_stage, - 1, - ) - ) - - for layer_idx in layers_range: - prefix = "model.layers." + str(layer_idx) + "." - tensorrt_llm.logger.info(f"Process weights in layer: {layer_idx}") - for idx, awq_attr in enumerate(awq_llama_block_names): - v = awq_llama[prefix + awq_attr] - layer = attrgetter(tensorrt_llm_llama_block_names[idx])( - tensorrt_llm_llama.layers[layer_idx] - ) - setattr(layer, "value", v.to(torch_dtype).cpu().numpy()) - - # Attention QKV Linear - # concatenate the Q, K, V layers weights. - process_and_assign_qkv_weight( - awq_llama, prefix, tensorrt_llm_llama.layers[layer_idx].attention.qkv - ) - - # Attention Dense (out_proj) Linear - mPrefix = prefix + "self_attn.o_proj" - mOp = tensorrt_llm_llama.layers[layer_idx].attention.dense - process_and_assign_weight(awq_llama, mPrefix, mOp, 0) - - # MLP up_proj (mlp.gate) Linear - mPrefix = prefix + "mlp.up_proj" - mOp = tensorrt_llm_llama.layers[layer_idx].mlp.gate - process_and_assign_weight(awq_llama, mPrefix, mOp, 1) - - # MLP down_proj (mlp.proj) Linear - mPrefix = prefix + "mlp.down_proj" - mOp = tensorrt_llm_llama.layers[layer_idx].mlp.proj - process_and_assign_weight(awq_llama, mPrefix, mOp, 0) - - # MLP gate_proj (mlp.fc) Linear - mPrefix = prefix + "mlp.gate_proj" - mOp = tensorrt_llm_llama.layers[layer_idx].mlp.fc - process_and_assign_weight(awq_llama, mPrefix, mOp, 1) - - v = awq_llama["model.norm.weight"] - if mapping.is_last_pp_rank(): - tensorrt_llm_llama.ln_f.weight.value = v.to(torch_dtype).cpu().numpy() - - # lm_head - if pad_vocab: - weight = awq_llama["lm_head.weight"] - [vocab_size, k] = weight.shape - new_weight = torch.zeros([pad_vocab_size, k]) - new_weight[:vocab_size, :] = weight - new_weight = new_weight.T.contiguous() - amax = awq_llama["lm_head.weight_quantizer._amax"].reshape( - [vocab_size, k // group_size] - ) - new_amax = torch.ones([pad_vocab_size, k // group_size]) - new_amax[:vocab_size, :] = amax - new_amax = new_amax.T.contiguous() - new_scale = new_amax / 8 - tensorrt_llm_llama.lm_head.qweight.value = AWQ_quantize_pack_preprocess( - new_weight, new_scale - ) - tensorrt_llm_llama.lm_head.scale.value = new_scale.to(torch_dtype).cpu().numpy() - tensorrt_llm_llama.lm_head.pre_quant_scale.value = ( - awq_llama["lm_head.input_quantizer._pre_quant_scale"] - .to(torch_dtype) - .cpu() - .numpy() - ) - else: - mPrefix = "lm_head" - mOp = tensorrt_llm_llama.lm_head - if mapping.is_last_pp_rank(): - process_and_assign_weight(awq_llama, mPrefix, mOp, 1) - - tok = time.time() - t = time.strftime("%H:%M:%S", time.gmtime(tok - tik)) - tensorrt_llm.logger.info(f"Weights loaded. Total time: {t}") diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/ensemble/config.pbtxt b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/ensemble/config.pbtxt deleted file mode 100755 index cbd087ce9..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/ensemble/config.pbtxt +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "ensemble" -platform: "ensemble" -max_batch_size: 128 -input [ - { - name: "text_input" - data_type: TYPE_STRING - dims: [ -1 ] - }, - { - name: "max_tokens" - data_type: TYPE_UINT32 - dims: [ -1 ] - }, - { - name: "end_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "pad_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "top_k" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "top_p" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "temperature" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "length_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "repetition_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "min_length" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "presence_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "random_seed" - data_type: TYPE_UINT64 - dims: [ 1 ] - optional: true - }, - { - name: "beam_width" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "stream" - data_type: TYPE_BOOL - dims: [ 1 ] - optional: true - } -] -output [ - { - name: "text_output" - data_type: TYPE_STRING - dims: [ -1, -1 ] - } -] -ensemble_scheduling { - step [ - { - model_name: "preprocessing" - model_version: -1 - input_map { - key: "QUERY" - value: "text_input" - } - input_map { - key: "REQUEST_OUTPUT_LEN" - value: "max_tokens" - } - output_map { - key: "REQUEST_INPUT_LEN" - value: "_REQUEST_INPUT_LEN" - } - output_map { - key: "INPUT_ID" - value: "_INPUT_ID" - } - output_map { - key: "REQUEST_OUTPUT_LEN" - value: "_REQUEST_OUTPUT_LEN" - } - }, - { - model_name: "tensorrt_llm" - model_version: -1 - input_map { - key: "input_ids" - value: "_INPUT_ID" - } - input_map { - key: "input_lengths" - value: "_REQUEST_INPUT_LEN" - } - input_map { - key: "request_output_len" - value: "_REQUEST_OUTPUT_LEN" - } - input_map { - key: "end_id" - value: "end_id" - } - input_map { - key: "pad_id" - value: "pad_id" - } - input_map { - key: "runtime_top_k" - value: "top_k" - } - input_map { - key: "runtime_top_p" - value: "top_p" - } - input_map { - key: "temperature" - value: "temperature" - } - input_map { - key: "len_penalty" - value: "length_penalty" - } - input_map { - key: "repetition_penalty" - value: "repetition_penalty" - } - input_map { - key: "min_length" - value: "min_length" - } - input_map { - key: "presence_penalty" - value: "presence_penalty" - } - input_map { - key: "random_seed" - value: "random_seed" - } - input_map { - key: "beam_width" - value: "beam_width" - } - input_map { - key: "streaming" - value: "stream" - } - output_map { - key: "output_ids" - value: "_TOKENS_BATCH" - } - }, - { - model_name: "postprocessing" - model_version: -1 - input_map { - key: "TOKENS_BATCH" - value: "_TOKENS_BATCH" - } - output_map { - key: "OUTPUT" - value: "text_output" - } - } - ] -} diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/postprocessing/1/model.py b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/postprocessing/1/model.py deleted file mode 100755 index bb8a73782..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/postprocessing/1/model.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- -import json -import os - -import numpy as np -import triton_python_backend_utils as pb_utils -from transformers import LlamaTokenizer - -TOKENIZER_DIR = os.environ.get("TOKENIZER_DIR", "/model") - -SPACE_CHAR = 9601 -NEWLINE_CHAR = 60 -STOP_TOKEN = 2 - - -class TritonPythonModel: - """Your Python model must use the same class name. Every Python model - that is created must have "TritonPythonModel" as the class name. - """ - - def initialize(self, args): - """`initialize` is called only once when the model is being loaded. - Implementing `initialize` function is optional. This function allows - the model to initialize any state associated with this model. - Parameters - ---------- - args : dict - Both keys and values are strings. The dictionary keys and values are: - * model_config: A JSON string containing the model configuration - * model_instance_kind: A string containing model instance kind - * model_instance_device_id: A string containing model instance device ID - * model_repository: Model repository path - * model_version: Model version - * model_name: Model name - """ - # Parse model configs - self.model_config = model_config = json.loads(args["model_config"]) - - # Parse model output configs - output_config = pb_utils.get_output_config_by_name(model_config, "OUTPUT") - - # Convert Triton types to numpy types - self.output_dtype = pb_utils.triton_string_to_numpy(output_config["data_type"]) - - self.tokenizer = LlamaTokenizer.from_pretrained(TOKENIZER_DIR, legacy=False) - vocab = self.tokenizer.convert_ids_to_tokens( - list(range(self.tokenizer.vocab_size)) - ) - - def execute(self, requests): - """`execute` must be implemented in every Python model. `execute` - function receives a list of pb_utils.InferenceRequest as the only - argument. This function is called when an inference is requested - for this model. Depending on the batching configuration (e.g. Dynamic - Batching) used, `requests` may contain multiple requests. Every - Python model, must create one pb_utils.InferenceResponse for every - pb_utils.InferenceRequest in `requests`. If there is an error, you can - set the error argument when creating a pb_utils.InferenceResponse. - Parameters - ---------- - requests : list - A list of pb_utils.InferenceRequest - Returns - ------- - list - A list of pb_utils.InferenceResponse. The length of this list must - be the same as `requests` - """ - - responses = [] - - # Every Python backend must iterate over everyone of the requests - # and create a pb_utils.InferenceResponse for each of them. - for request in requests: - # Get input tensors - tokens_batch = pb_utils.get_input_tensor_by_name( - request, "TOKENS_BATCH" - ).as_numpy() - - # Reshape Input - # tokens_batch = tokens_batch.reshape([-1, tokens_batch.shape[0]]) - # tokens_batch = tokens_batch.T - - # Postprocessing output data. - outputs = self._postprocessing(tokens_batch) - - # Create output tensors. You need pb_utils.Tensor - # objects to create pb_utils.InferenceResponse. - output_tensor = pb_utils.Tensor( - "OUTPUT", np.array(outputs).astype(self.output_dtype) - ) - - # Create InferenceResponse. You can set an error here in case - # there was a problem with handling this inference request. - # Below is an example of how you can set errors in inference - # response: - # - # pb_utils.InferenceResponse( - # output_tensors=..., TritonError("An error occurred")) - inference_response = pb_utils.InferenceResponse( - output_tensors=[output_tensor] - ) - responses.append(inference_response) - - # You should return a list of pb_utils.InferenceResponse. Length - # of this list must match the length of `requests` list. - return responses - - def finalize(self): - """`finalize` is called only once when the model is being unloaded. - `Implementing `finalize` function is optional. This function allows - the model to perform any necessary clean ups before exit. - """ - pb_utils.Logger.log("Finalizing the Post-Processing Model.") - - def _id_to_token(self, token_id): - # handle special tokens (end of string, unknown, etc) - try: - special_token_index = self.tokenizer.all_special_ids.index(token_id) - return self.tokenizer.all_special_tokens[special_token_index] - except ValueError: - pass - - # handle typical tokens - tokens = self.tokenizer.convert_ids_to_tokens(token_id) - if ord(tokens[0]) == SPACE_CHAR: - return f" {tokens[1:]}" - if ord(tokens[0]) == NEWLINE_CHAR: - return "\n" - return tokens - - def _postprocessing(self, tokens_batch): - tokens_batch = tokens_batch.tolist() - return [ - self._id_to_token(token_id) - for beam_tokens in tokens_batch - for token_ids in beam_tokens - for token_id in token_ids - ] - - # for beam_tokens in tokens_batch: - # for token_ids in beam_tokens: - # for token_id in token_ids: - # # handle special tokens (end of string, unknown, etc) - # special_token = self.tokenizer.added_tokens_decoder.get(token_id) - # if special_token: - # tokens = special_token.content - - # # handle typical tokens - # else: - # tokens = self.tokenizer.convert_ids_to_tokens(token_id) - # if ord(tokens[0]) == SPACE_CHAR: - # tokens = f" {tokens[1:]}" - # elif ord(tokens[0]) == NEWLINE_CHAR: - # tokens = "\n" - - # outputs.append(tokens) - # return outputs diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/postprocessing/config.pbtxt b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/postprocessing/config.pbtxt deleted file mode 100755 index 3c3ea10d4..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/postprocessing/config.pbtxt +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "postprocessing" -backend: "python" -max_batch_size: 128 -input [ - { - name: "TOKENS_BATCH" - data_type: TYPE_INT32 - dims: [ -1, -1 ] - } -] -output [ - { - name: "OUTPUT" - data_type: TYPE_STRING - dims: [ -1, -1 ] - } -] - -instance_group [ - { - count: 1 - kind: KIND_CPU - } -] diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/preprocessing/1/model.py b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/preprocessing/1/model.py deleted file mode 100644 index 44e8b9c4a..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/preprocessing/1/model.py +++ /dev/null @@ -1,244 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import csv -import json -import os - -import numpy as np -import torch -import triton_python_backend_utils as pb_utils -from torch.nn.utils.rnn import pad_sequence -from transformers import LlamaTokenizer - -TOKENIZER_DIR = os.environ.get("TOKENIZER_DIR", "/model") - -END_ID = 2 - -# SYSTEM_PROMPT = ( -# """You are a helpful, respectful and honest assistant.""" -# """Always answer as helpfully as possible, while being safe.""" -# """Please ensure that your responses are positive in nature.""" -# ) - -# LLAMA_PROMPT_TEMPLATE = ( -# "[INST] <>" -# "{system_prompt}" -# "<>" -# "[/INST] {context} [INST] {question} [/INST]" -# ) - - -class TritonPythonModel: - """Your Python model must use the same class name. Every Python model - that is created must have "TritonPythonModel" as the class name. - """ - - def initialize(self, args): - """`initialize` is called only once when the model is being loaded. - Implementing `initialize` function is optional. This function allows - the model to initialize any state associated with this model. - Parameters - ---------- - args : dict - Both keys and values are strings. The dictionary keys and values are: - * model_config: A JSON string containing the model configuration - * model_instance_kind: A string containing model instance kind - * model_instance_device_id: A string containing model instance device ID - * model_repository: Model repository path - * model_version: Model version - * model_name: Model name - """ - # Parse model configs - self.model_config = model_config = json.loads(args["model_config"]) - - # Parse model output configs and convert Triton types to numpy types - input_names = ["INPUT_ID", "REQUEST_INPUT_LEN"] - for input_name in input_names: - setattr( - self, - input_name.lower() + "_dtype", - pb_utils.triton_string_to_numpy( - pb_utils.get_output_config_by_name(model_config, input_name)[ - "data_type" - ] - ), - ) - - self.encoder = LlamaTokenizer.from_pretrained(TOKENIZER_DIR, legacy=False) - - def execute(self, requests): - """`execute` must be implemented in every Python model. `execute` - function receives a list of pb_utils.InferenceRequest as the only - argument. This function is called when an inference is requested - for this model. Depending on the batching configuration (e.g. Dynamic - Batching) used, `requests` may contain multiple requests. Every - Python model, must create one pb_utils.InferenceResponse for every - pb_utils.InferenceRequest in `requests`. If there is an error, you can - set the error argument when creating a pb_utils.InferenceResponse. - Parameters - ---------- - requests : list - A list of pb_utils.InferenceRequest - Returns - ------- - list - A list of pb_utils.InferenceResponse. The length of this list must - be the same as `requests` - """ - - responses = [] - - # Every Python backend must iterate over everyone of the requests - # and create a pb_utils.InferenceResponse for each of them. - for request in requests: - # Get input tensors - query = pb_utils.get_input_tensor_by_name(request, "QUERY").as_numpy() - request_output_len = pb_utils.get_input_tensor_by_name( - request, "REQUEST_OUTPUT_LEN" - ).as_numpy() - - input_id, request_input_len = self._create_request(query) - - # Create output tensors. You need pb_utils.Tensor - # objects to create pb_utils.InferenceResponse. - input_id_tensor = pb_utils.Tensor( - "INPUT_ID", np.array(input_id).astype(self.input_id_dtype) - ) - request_input_len_tensor = pb_utils.Tensor( - "REQUEST_INPUT_LEN", - np.array(request_input_len).astype(self.request_input_len_dtype), - ) - request_output_len_tensor = pb_utils.Tensor( - "REQUEST_OUTPUT_LEN", request_output_len - ) - - # Create InferenceResponse. You can set an error here in case - # there was a problem with handling this inference request. - # Below is an example of how you can set errors in inference - # response: - # - # pb_utils.InferenceResponse( - # output_tensors=..., TritonError("An error occurred")) - inference_response = pb_utils.InferenceResponse( - output_tensors=[ - input_id_tensor, - request_input_len_tensor, - request_output_len_tensor, - ] - ) - responses.append(inference_response) - - # You should return a list of pb_utils.InferenceResponse. Length - # of this list must match the length of `requests` list. - return responses - - def finalize(self): - """`finalize` is called only once when the model is being unloaded. - Implementing `finalize` function is optional. This function allows - the model to perform any necessary clean ups before exit. - """ - pb_utils.Logger.log("Finalizing the Pre-Processing Model.") - - def _create_request(self, prompts): - """ - prompts : batch string (2D numpy array) - """ - - start_ids = [ - torch.IntTensor(self.encoder.encode(prompt[0].decode())) - for prompt in prompts - ] - - start_lengths = torch.IntTensor([[len(ids)] for ids in start_ids]) - - start_ids = pad_sequence(start_ids, batch_first=True, padding_value=END_ID) - - return start_ids, start_lengths - - def _create_word_list(self, word_dict): - flat_ids = [] - offsets = [] - for word_dict_item in word_dict: - item_flat_ids = [] - item_offsets = [] - - words = list(csv.reader([word_dict_item[0].decode()]))[0] - for word in words: - ids = self._encode(word) - - if len(ids) == 0: - continue - - item_flat_ids += ids - item_offsets.append(len(ids)) - - flat_ids.append(np.array(item_flat_ids)) - offsets.append(np.cumsum(np.array(item_offsets))) - - pad_to = max(1, max(len(ids) for ids in flat_ids)) - - for i, (ids, offs) in enumerate(zip(flat_ids, offsets)): - flat_ids[i] = np.pad(ids, (0, pad_to - len(ids)), constant_values=0) - offsets[i] = np.pad(offs, (0, pad_to - len(offs)), constant_values=-1) - - return np.array([flat_ids, offsets], dtype="int32").transpose((1, 0, 2)) - - def to_word_list_format(self, word_dict): - flat_ids = [] - offsets = [] - for word_dict_item in word_dict: - item_flat_ids = [] - item_offsets = [] - - if isinstance(word_dict_item[0], bytes): - word_dict_item = [word_dict_item[0].decode()] - - words = list(csv.reader(word_dict_item))[0] - for word in words: - ids = self.encoder.encode(word) - - if len(ids) == 0: - continue - - item_flat_ids += ids - item_offsets.append(len(ids)) - - flat_ids.append(np.array(item_flat_ids)) - offsets.append(np.cumsum(np.array(item_offsets))) - - pad_to = max(1, max(len(ids) for ids in flat_ids)) - - for i, (ids, offs) in enumerate(zip(flat_ids, offsets)): - flat_ids[i] = np.pad(ids, (0, pad_to - len(ids)), constant_values=0) - offsets[i] = np.pad(offs, (0, pad_to - len(offs)), constant_values=-1) - - return np.array([flat_ids, offsets], dtype="int32").transpose((1, 0, 2)) - - def _encode(self, sentence): - sentence = sentence.decode() if isinstance(sentence, bytes) else sentence - return self.encoder.encode(sentence) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/preprocessing/config.pbtxt b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/preprocessing/config.pbtxt deleted file mode 100644 index d2e3029a9..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/preprocessing/config.pbtxt +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "preprocessing" -backend: "python" -max_batch_size: 128 -input [ - { - name: "QUERY" - data_type: TYPE_STRING - dims: [ -1 ] - }, - { - name: "REQUEST_OUTPUT_LEN" - data_type: TYPE_UINT32 - dims: [ -1 ] - } -] -output [ - { - name: "INPUT_ID" - data_type: TYPE_INT32 - dims: [ -1 ] - }, - { - name: "REQUEST_INPUT_LEN" - data_type: TYPE_INT32 - dims: [ 1 ] - }, - { - name: "REQUEST_OUTPUT_LEN" - data_type: TYPE_UINT32 - dims: [ -1 ] - } -] - -instance_group [ - { - count: 1 - kind: KIND_CPU - } -] diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/tensorrt_llm/1/.gitkeep b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/tensorrt_llm/1/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/tensorrt_llm/config.pbtxt.j2 b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/tensorrt_llm/config.pbtxt.j2 deleted file mode 100644 index 4b719b046..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/tensorrt_llm/config.pbtxt.j2 +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "tensorrt_llm" -backend: "tensorrtllm" -max_batch_size: 128 - -model_transaction_policy { - decoupled: {{ decoupled_mode }} -} - -input [ - { - name: "input_ids" - data_type: TYPE_INT32 - dims: [ -1 ] - }, - { - name: "input_lengths" - data_type: TYPE_INT32 - dims: [ 1 ] - reshape: { shape: [ ] } - }, - { - name: "request_output_len" - data_type: TYPE_UINT32 - dims: [ 1 ] - }, - { - name: "end_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "pad_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "beam_width" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "temperature" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "runtime_top_k" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "runtime_top_p" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "len_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "repetition_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "min_length" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "presence_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "random_seed" - data_type: TYPE_UINT64 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "stop" - data_type: TYPE_BOOL - dims: [ 1 ] - optional: true - }, - { - name: "streaming" - data_type: TYPE_BOOL - dims: [ 1 ] - optional: true - } -] -output [ - { - name: "output_ids" - data_type: TYPE_INT32 - dims: [ -1, -1 ] - } -] -instance_group [ - { - count: 1 - kind : KIND_CPU - } -] -parameters: { - key: "max_beam_width" - value: { - string_value: "1" - } -} -parameters: { - key: "FORCE_CPU_ONLY_INPUT_TENSORS" - value: { - string_value: "no" - } -} -parameters: { - key: "gpt_model_type" - value: { - string_value: "{{ gpt_model_type }}" - } -} -parameters: { - key: "gpt_model_path" - value: { - string_value: "{{ engine_dir }}" - } -} -parameters: { - key: "max_tokens_in_paged_kv_cache" - value: { - string_value: "" - } -} -parameters: { - key: "batch_scheduler_policy" - value: { - string_value: "guaranteed_completion" - } -} -parameters: { - key: "kv_cache_free_gpu_mem_fraction" - value: { - string_value: ".75" - } -} -parameters: { - key: "max_num_sequences" - value: { - string_value: "" - } -} -parameters: { - key: "enable_trt_overlap" - value: { - string_value: "" - } -} diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/ensemble/1/.tmp b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/ensemble/1/.tmp deleted file mode 100644 index e69de29bb..000000000 diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/ensemble/config.pbtxt b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/ensemble/config.pbtxt deleted file mode 100755 index cbd087ce9..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/ensemble/config.pbtxt +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "ensemble" -platform: "ensemble" -max_batch_size: 128 -input [ - { - name: "text_input" - data_type: TYPE_STRING - dims: [ -1 ] - }, - { - name: "max_tokens" - data_type: TYPE_UINT32 - dims: [ -1 ] - }, - { - name: "end_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "pad_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "top_k" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "top_p" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "temperature" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "length_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "repetition_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "min_length" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "presence_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - optional: true - }, - { - name: "random_seed" - data_type: TYPE_UINT64 - dims: [ 1 ] - optional: true - }, - { - name: "beam_width" - data_type: TYPE_UINT32 - dims: [ 1 ] - optional: true - }, - { - name: "stream" - data_type: TYPE_BOOL - dims: [ 1 ] - optional: true - } -] -output [ - { - name: "text_output" - data_type: TYPE_STRING - dims: [ -1, -1 ] - } -] -ensemble_scheduling { - step [ - { - model_name: "preprocessing" - model_version: -1 - input_map { - key: "QUERY" - value: "text_input" - } - input_map { - key: "REQUEST_OUTPUT_LEN" - value: "max_tokens" - } - output_map { - key: "REQUEST_INPUT_LEN" - value: "_REQUEST_INPUT_LEN" - } - output_map { - key: "INPUT_ID" - value: "_INPUT_ID" - } - output_map { - key: "REQUEST_OUTPUT_LEN" - value: "_REQUEST_OUTPUT_LEN" - } - }, - { - model_name: "tensorrt_llm" - model_version: -1 - input_map { - key: "input_ids" - value: "_INPUT_ID" - } - input_map { - key: "input_lengths" - value: "_REQUEST_INPUT_LEN" - } - input_map { - key: "request_output_len" - value: "_REQUEST_OUTPUT_LEN" - } - input_map { - key: "end_id" - value: "end_id" - } - input_map { - key: "pad_id" - value: "pad_id" - } - input_map { - key: "runtime_top_k" - value: "top_k" - } - input_map { - key: "runtime_top_p" - value: "top_p" - } - input_map { - key: "temperature" - value: "temperature" - } - input_map { - key: "len_penalty" - value: "length_penalty" - } - input_map { - key: "repetition_penalty" - value: "repetition_penalty" - } - input_map { - key: "min_length" - value: "min_length" - } - input_map { - key: "presence_penalty" - value: "presence_penalty" - } - input_map { - key: "random_seed" - value: "random_seed" - } - input_map { - key: "beam_width" - value: "beam_width" - } - input_map { - key: "streaming" - value: "stream" - } - output_map { - key: "output_ids" - value: "_TOKENS_BATCH" - } - }, - { - model_name: "postprocessing" - model_version: -1 - input_map { - key: "TOKENS_BATCH" - value: "_TOKENS_BATCH" - } - output_map { - key: "OUTPUT" - value: "text_output" - } - } - ] -} diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/postprocessing/1/model.py b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/postprocessing/1/model.py deleted file mode 100755 index 0e563c960..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/postprocessing/1/model.py +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: utf-8 -*- -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -import os - -import numpy as np -import triton_python_backend_utils as pb_utils -from transformers import LlamaTokenizer - -TOKENIZER_DIR = os.environ.get("TOKENIZER_DIR", "/model") - -SPACE_CHAR = 9601 -NEWLINE_CHAR = 60 -STOP_TOKEN = 2 - - -class TritonPythonModel: - """Your Python model must use the same class name. Every Python model - that is created must have "TritonPythonModel" as the class name. - """ - - def initialize(self, args): - """`initialize` is called only once when the model is being loaded. - Implementing `initialize` function is optional. This function allows - the model to initialize any state associated with this model. - Parameters - ---------- - args : dict - Both keys and values are strings. The dictionary keys and values are: - * model_config: A JSON string containing the model configuration - * model_instance_kind: A string containing model instance kind - * model_instance_device_id: A string containing model instance device ID - * model_repository: Model repository path - * model_version: Model version - * model_name: Model name - """ - # Parse model configs - self.model_config = model_config = json.loads(args["model_config"]) - - # Parse model output configs - output_config = pb_utils.get_output_config_by_name(model_config, "OUTPUT") - - # Convert Triton types to numpy types - self.output_dtype = pb_utils.triton_string_to_numpy(output_config["data_type"]) - - self.tokenizer = LlamaTokenizer.from_pretrained(TOKENIZER_DIR, legacy=False) - vocab = self.tokenizer.convert_ids_to_tokens( - list(range(self.tokenizer.vocab_size)) - ) - - def execute(self, requests): - """`execute` must be implemented in every Python model. `execute` - function receives a list of pb_utils.InferenceRequest as the only - argument. This function is called when an inference is requested - for this model. Depending on the batching configuration (e.g. Dynamic - Batching) used, `requests` may contain multiple requests. Every - Python model, must create one pb_utils.InferenceResponse for every - pb_utils.InferenceRequest in `requests`. If there is an error, you can - set the error argument when creating a pb_utils.InferenceResponse. - Parameters - ---------- - requests : list - A list of pb_utils.InferenceRequest - Returns - ------- - list - A list of pb_utils.InferenceResponse. The length of this list must - be the same as `requests` - """ - - responses = [] - - # Every Python backend must iterate over everyone of the requests - # and create a pb_utils.InferenceResponse for each of them. - for request in requests: - # Get input tensors - tokens_batch = pb_utils.get_input_tensor_by_name( - request, "TOKENS_BATCH" - ).as_numpy() - - # Reshape Input - # tokens_batch = tokens_batch.reshape([-1, tokens_batch.shape[0]]) - # tokens_batch = tokens_batch.T - - # Postprocessing output data. - outputs = self._postprocessing(tokens_batch) - - # Create output tensors. You need pb_utils.Tensor - # objects to create pb_utils.InferenceResponse. - output_tensor = pb_utils.Tensor( - "OUTPUT", np.array(outputs).astype(self.output_dtype) - ) - - # Create InferenceResponse. You can set an error here in case - # there was a problem with handling this inference request. - # Below is an example of how you can set errors in inference - # response: - # - # pb_utils.InferenceResponse( - # output_tensors=..., TritonError("An error occurred")) - inference_response = pb_utils.InferenceResponse( - output_tensors=[output_tensor] - ) - responses.append(inference_response) - - # You should return a list of pb_utils.InferenceResponse. Length - # of this list must match the length of `requests` list. - return responses - - def finalize(self): - """`finalize` is called only once when the model is being unloaded. - `Implementing `finalize` function is optional. This function allows - the model to perform any necessary clean ups before exit. - """ - pb_utils.Logger.log("Finalizing the Post-Processing Model.") - - def _id_to_token(self, token_id): - # handle special tokens (end of string, unknown, etc) - try: - special_token_index = self.tokenizer.all_special_ids.index(token_id) - return self.tokenizer.all_special_tokens[special_token_index] - except ValueError: - pass - - # handle typical tokens - tokens = self.tokenizer.convert_ids_to_tokens(token_id) - if ord(tokens[0]) == SPACE_CHAR: - return f" {tokens[1:]}" - if ord(tokens[0]) == NEWLINE_CHAR: - return "\n" - return tokens - - def _postprocessing(self, tokens_batch): - tokens_batch = tokens_batch.tolist() - return [ - self._id_to_token(token_id) - for beam_tokens in tokens_batch - for token_ids in beam_tokens - for token_id in token_ids - ] - - # for beam_tokens in tokens_batch: - # for token_ids in beam_tokens: - # for token_id in token_ids: - # # handle special tokens (end of string, unknown, etc) - # special_token = self.tokenizer.added_tokens_decoder.get(token_id) - # if special_token: - # tokens = special_token.content - - # # handle typical tokens - # else: - # tokens = self.tokenizer.convert_ids_to_tokens(token_id) - # if ord(tokens[0]) == SPACE_CHAR: - # tokens = f" {tokens[1:]}" - # elif ord(tokens[0]) == NEWLINE_CHAR: - # tokens = "\n" - - # outputs.append(tokens) - # return outputs diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/postprocessing/config.pbtxt b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/postprocessing/config.pbtxt deleted file mode 100755 index 3c3ea10d4..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/postprocessing/config.pbtxt +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "postprocessing" -backend: "python" -max_batch_size: 128 -input [ - { - name: "TOKENS_BATCH" - data_type: TYPE_INT32 - dims: [ -1, -1 ] - } -] -output [ - { - name: "OUTPUT" - data_type: TYPE_STRING - dims: [ -1, -1 ] - } -] - -instance_group [ - { - count: 1 - kind: KIND_CPU - } -] diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/preprocessing/1/model.py b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/preprocessing/1/model.py deleted file mode 100644 index 44e8b9c4a..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/preprocessing/1/model.py +++ /dev/null @@ -1,244 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import csv -import json -import os - -import numpy as np -import torch -import triton_python_backend_utils as pb_utils -from torch.nn.utils.rnn import pad_sequence -from transformers import LlamaTokenizer - -TOKENIZER_DIR = os.environ.get("TOKENIZER_DIR", "/model") - -END_ID = 2 - -# SYSTEM_PROMPT = ( -# """You are a helpful, respectful and honest assistant.""" -# """Always answer as helpfully as possible, while being safe.""" -# """Please ensure that your responses are positive in nature.""" -# ) - -# LLAMA_PROMPT_TEMPLATE = ( -# "[INST] <>" -# "{system_prompt}" -# "<>" -# "[/INST] {context} [INST] {question} [/INST]" -# ) - - -class TritonPythonModel: - """Your Python model must use the same class name. Every Python model - that is created must have "TritonPythonModel" as the class name. - """ - - def initialize(self, args): - """`initialize` is called only once when the model is being loaded. - Implementing `initialize` function is optional. This function allows - the model to initialize any state associated with this model. - Parameters - ---------- - args : dict - Both keys and values are strings. The dictionary keys and values are: - * model_config: A JSON string containing the model configuration - * model_instance_kind: A string containing model instance kind - * model_instance_device_id: A string containing model instance device ID - * model_repository: Model repository path - * model_version: Model version - * model_name: Model name - """ - # Parse model configs - self.model_config = model_config = json.loads(args["model_config"]) - - # Parse model output configs and convert Triton types to numpy types - input_names = ["INPUT_ID", "REQUEST_INPUT_LEN"] - for input_name in input_names: - setattr( - self, - input_name.lower() + "_dtype", - pb_utils.triton_string_to_numpy( - pb_utils.get_output_config_by_name(model_config, input_name)[ - "data_type" - ] - ), - ) - - self.encoder = LlamaTokenizer.from_pretrained(TOKENIZER_DIR, legacy=False) - - def execute(self, requests): - """`execute` must be implemented in every Python model. `execute` - function receives a list of pb_utils.InferenceRequest as the only - argument. This function is called when an inference is requested - for this model. Depending on the batching configuration (e.g. Dynamic - Batching) used, `requests` may contain multiple requests. Every - Python model, must create one pb_utils.InferenceResponse for every - pb_utils.InferenceRequest in `requests`. If there is an error, you can - set the error argument when creating a pb_utils.InferenceResponse. - Parameters - ---------- - requests : list - A list of pb_utils.InferenceRequest - Returns - ------- - list - A list of pb_utils.InferenceResponse. The length of this list must - be the same as `requests` - """ - - responses = [] - - # Every Python backend must iterate over everyone of the requests - # and create a pb_utils.InferenceResponse for each of them. - for request in requests: - # Get input tensors - query = pb_utils.get_input_tensor_by_name(request, "QUERY").as_numpy() - request_output_len = pb_utils.get_input_tensor_by_name( - request, "REQUEST_OUTPUT_LEN" - ).as_numpy() - - input_id, request_input_len = self._create_request(query) - - # Create output tensors. You need pb_utils.Tensor - # objects to create pb_utils.InferenceResponse. - input_id_tensor = pb_utils.Tensor( - "INPUT_ID", np.array(input_id).astype(self.input_id_dtype) - ) - request_input_len_tensor = pb_utils.Tensor( - "REQUEST_INPUT_LEN", - np.array(request_input_len).astype(self.request_input_len_dtype), - ) - request_output_len_tensor = pb_utils.Tensor( - "REQUEST_OUTPUT_LEN", request_output_len - ) - - # Create InferenceResponse. You can set an error here in case - # there was a problem with handling this inference request. - # Below is an example of how you can set errors in inference - # response: - # - # pb_utils.InferenceResponse( - # output_tensors=..., TritonError("An error occurred")) - inference_response = pb_utils.InferenceResponse( - output_tensors=[ - input_id_tensor, - request_input_len_tensor, - request_output_len_tensor, - ] - ) - responses.append(inference_response) - - # You should return a list of pb_utils.InferenceResponse. Length - # of this list must match the length of `requests` list. - return responses - - def finalize(self): - """`finalize` is called only once when the model is being unloaded. - Implementing `finalize` function is optional. This function allows - the model to perform any necessary clean ups before exit. - """ - pb_utils.Logger.log("Finalizing the Pre-Processing Model.") - - def _create_request(self, prompts): - """ - prompts : batch string (2D numpy array) - """ - - start_ids = [ - torch.IntTensor(self.encoder.encode(prompt[0].decode())) - for prompt in prompts - ] - - start_lengths = torch.IntTensor([[len(ids)] for ids in start_ids]) - - start_ids = pad_sequence(start_ids, batch_first=True, padding_value=END_ID) - - return start_ids, start_lengths - - def _create_word_list(self, word_dict): - flat_ids = [] - offsets = [] - for word_dict_item in word_dict: - item_flat_ids = [] - item_offsets = [] - - words = list(csv.reader([word_dict_item[0].decode()]))[0] - for word in words: - ids = self._encode(word) - - if len(ids) == 0: - continue - - item_flat_ids += ids - item_offsets.append(len(ids)) - - flat_ids.append(np.array(item_flat_ids)) - offsets.append(np.cumsum(np.array(item_offsets))) - - pad_to = max(1, max(len(ids) for ids in flat_ids)) - - for i, (ids, offs) in enumerate(zip(flat_ids, offsets)): - flat_ids[i] = np.pad(ids, (0, pad_to - len(ids)), constant_values=0) - offsets[i] = np.pad(offs, (0, pad_to - len(offs)), constant_values=-1) - - return np.array([flat_ids, offsets], dtype="int32").transpose((1, 0, 2)) - - def to_word_list_format(self, word_dict): - flat_ids = [] - offsets = [] - for word_dict_item in word_dict: - item_flat_ids = [] - item_offsets = [] - - if isinstance(word_dict_item[0], bytes): - word_dict_item = [word_dict_item[0].decode()] - - words = list(csv.reader(word_dict_item))[0] - for word in words: - ids = self.encoder.encode(word) - - if len(ids) == 0: - continue - - item_flat_ids += ids - item_offsets.append(len(ids)) - - flat_ids.append(np.array(item_flat_ids)) - offsets.append(np.cumsum(np.array(item_offsets))) - - pad_to = max(1, max(len(ids) for ids in flat_ids)) - - for i, (ids, offs) in enumerate(zip(flat_ids, offsets)): - flat_ids[i] = np.pad(ids, (0, pad_to - len(ids)), constant_values=0) - offsets[i] = np.pad(offs, (0, pad_to - len(offs)), constant_values=-1) - - return np.array([flat_ids, offsets], dtype="int32").transpose((1, 0, 2)) - - def _encode(self, sentence): - sentence = sentence.decode() if isinstance(sentence, bytes) else sentence - return self.encoder.encode(sentence) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/preprocessing/config.pbtxt b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/preprocessing/config.pbtxt deleted file mode 100644 index d2e3029a9..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/preprocessing/config.pbtxt +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "preprocessing" -backend: "python" -max_batch_size: 128 -input [ - { - name: "QUERY" - data_type: TYPE_STRING - dims: [ -1 ] - }, - { - name: "REQUEST_OUTPUT_LEN" - data_type: TYPE_UINT32 - dims: [ -1 ] - } -] -output [ - { - name: "INPUT_ID" - data_type: TYPE_INT32 - dims: [ -1 ] - }, - { - name: "REQUEST_INPUT_LEN" - data_type: TYPE_INT32 - dims: [ 1 ] - }, - { - name: "REQUEST_OUTPUT_LEN" - data_type: TYPE_UINT32 - dims: [ -1 ] - } -] - -instance_group [ - { - count: 1 - kind: KIND_CPU - } -] diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/tensorrt_llm/1/.gitkeep b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/tensorrt_llm/1/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/tensorrt_llm/config.pbtxt.j2 b/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/tensorrt_llm/config.pbtxt.j2 deleted file mode 100644 index 4b719b046..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/llama/tensorrt_llm/config.pbtxt.j2 +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of NVIDIA CORPORATION nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -name: "tensorrt_llm" -backend: "tensorrtllm" -max_batch_size: 128 - -model_transaction_policy { - decoupled: {{ decoupled_mode }} -} - -input [ - { - name: "input_ids" - data_type: TYPE_INT32 - dims: [ -1 ] - }, - { - name: "input_lengths" - data_type: TYPE_INT32 - dims: [ 1 ] - reshape: { shape: [ ] } - }, - { - name: "request_output_len" - data_type: TYPE_UINT32 - dims: [ 1 ] - }, - { - name: "end_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "pad_id" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "beam_width" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "temperature" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "runtime_top_k" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "runtime_top_p" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "len_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "repetition_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "min_length" - data_type: TYPE_UINT32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "presence_penalty" - data_type: TYPE_FP32 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "random_seed" - data_type: TYPE_UINT64 - dims: [ 1 ] - reshape: { shape: [ ] } - optional: true - }, - { - name: "stop" - data_type: TYPE_BOOL - dims: [ 1 ] - optional: true - }, - { - name: "streaming" - data_type: TYPE_BOOL - dims: [ 1 ] - optional: true - } -] -output [ - { - name: "output_ids" - data_type: TYPE_INT32 - dims: [ -1, -1 ] - } -] -instance_group [ - { - count: 1 - kind : KIND_CPU - } -] -parameters: { - key: "max_beam_width" - value: { - string_value: "1" - } -} -parameters: { - key: "FORCE_CPU_ONLY_INPUT_TENSORS" - value: { - string_value: "no" - } -} -parameters: { - key: "gpt_model_type" - value: { - string_value: "{{ gpt_model_type }}" - } -} -parameters: { - key: "gpt_model_path" - value: { - string_value: "{{ engine_dir }}" - } -} -parameters: { - key: "max_tokens_in_paged_kv_cache" - value: { - string_value: "" - } -} -parameters: { - key: "batch_scheduler_policy" - value: { - string_value: "guaranteed_completion" - } -} -parameters: { - key: "kv_cache_free_gpu_mem_fraction" - value: { - string_value: ".75" - } -} -parameters: { - key: "max_num_sequences" - value: { - string_value: "" - } -} -parameters: { - key: "enable_trt_overlap" - value: { - string_value: "" - } -} diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/__init__.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/__init__.py deleted file mode 100644 index f0aa9420a..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/__init__.py +++ /dev/null @@ -1,93 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Model-Server converts LLMs to TensorRT engines and hosts them with Triton.""" -import argparse -import logging - -from .conversion import ConversionOptions, convert -from .errors import ModelServerException -from .model import Model, ModelFormats -from .server import ModelServer - -_LOGGER = logging.getLogger(__name__) - - -def _should_convert(args: argparse.Namespace, model: "Model") -> bool: - """Determine if the conversion step should run.""" - if args.force_conversion: - return True - - if args.no_conversion: - return False - - return model.conversion_is_needed() - - -def main(args: argparse.Namespace) -> int: - """Execute the model server.""" - - # load the model directory - _LOGGER.info("Reading the model directory.") - model = Model(model_type=args.type, world_size=args.world_size) - - if model._format == ModelFormats.UNKNOWN: - raise ModelServerException( - f"""No known model formats detected in the provided MODEL_DIRECTORY. - Supported formats are Pytorch(.pth or .pt), Huggingface (.bin) and Onnx (.onnx). - Please check if the absolute path provided with the help of environment variable - MODEL_DIRECTORY in compose.env file is correct and has been set properly.""" - ) - - # calculate the default parallism parameters - if not args.tensor_parallelism: - args.tensor_parallelism = max( - int(model.world_size / args.pipeline_parallelism), 1 - ) - if args.pipeline_parallelism * args.tensor_parallelism != model.world_size: - raise ModelServerException( - "Tensor Parallelism * Pipeline Parallelism must be equal to World Size" - ) - - conversion_opts = ConversionOptions( - max_input_length=args.max_input_length, - max_output_length=args.max_output_length, - tensor_parallelism=args.tensor_parallelism, - pipline_parallelism=args.pipeline_parallelism, - quantization = args.quantization, - ) - - # print discovered model parameters - _LOGGER.info("Model file format: %s", model.format.name) - _LOGGER.info("World Size: %d", model.world_size) - _LOGGER.info("Max input length: %s", args.max_input_length) - _LOGGER.info("Max output length: %s", args.max_output_length) - _LOGGER.info("Compute Capability: %s", model.compute_cap) - _LOGGER.info("Quantization: %s", conversion_opts.quantization) - - # convert model - if _should_convert(args, model): - _LOGGER.info("Starting TensorRT Conversion.") - convert(model, conversion_opts) - else: - _LOGGER.info("TensorRT Conversion not required. Skipping.") - - # host model - if not args.no_hosting: - _LOGGER.info("Starting Triton Inference Server.") - inference_server = ModelServer(model, args.http) - return inference_server.run() - - return 0 diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/__main__.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/__main__.py deleted file mode 100644 index a72a7a005..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/__main__.py +++ /dev/null @@ -1,203 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Main entrypoint for the model-server application.""" -import argparse -import logging -import os -import sys - -from . import main -from .errors import ModelServerException -from .model import ModelTypes - -TERMINATION_LOG = "/dev/termination-log" - -_LOG_FMT = f"[{os.getpid()}] %(asctime)15s [%(levelname)7s] - %(name)s - %(message)s" -_LOG_DATE_FMT = "%b %d %H:%M:%S" -_LOGGER = logging.getLogger("main") - - -def parse_args() -> argparse.Namespace: - """Parse the comamnd line arguments.""" - parser = argparse.ArgumentParser( - prog="model-server", - description="Ingest models and host them with NVIDIA TensorRT LLM", - ) - - # options - parser.add_argument( - "-w", - "--world-size", - default=None, - type=int, - help="The number of GPUs to shard the model across. " - + "By default, this value will be equal to the number of available GPUs.", - ) - parser.add_argument( - "--force-conversion", - action="store_true", - help="When this flag is set, the TensorRT engine conversion will occur, " - + "even if a valid engine is in the cache.", - ) - parser.add_argument( - "--no-conversion", - action="store_true", - help="Skip the conversion. If no engine is available in the cache, an error will be raised.", - ) - parser.add_argument( - "--no-hosting", - action="store_true", - help="Do not start the Triton Inference Server. Only convert the model then exit.", - ) - parser.add_argument( - "-v", - "--verbose", - action="count", - default=1, - help="increase output verbosity", - ) - parser.add_argument( - "-q", - "--quiet", - action="count", - default=0, - help="decrease output verbosity", - ) - - # builder customization - parser.add_argument( - "--max-input-length", - type=int, - default=3000, - help="maximum number of input tokens", - ) - parser.add_argument( - "--max-output-length", - type=int, - default=512, - help="maximum number of output tokens", - ) - parser.add_argument( - "--tensor-parallelism", - type=int, - default=None, - help="number of tensor parallelism divisions (default: world_size/pipeline_parallelism)", - ) - parser.add_argument( - "--pipeline-parallelism", - type=int, - default=1, - help="number of pipeline parallism divisions (default: 1)", - ) - - parser.add_argument( - "--quantization", - type=str, - default=None, - help="Quantization type to be used for LLMs", - ) - - # server customization - parser.add_argument( - "--http", - action="store_true", - help="change the api server to http instead of grpc (note: this will disable token streaming)", - ) - - # positional arguments - supported_model_types = [e.name.lower().replace("_", "-") for e in ModelTypes] - parser.add_argument( - "type", - metavar="TYPE", - choices=supported_model_types, - type=str.lower, - help=f"{supported_model_types} The type of model to process.", - ) - - args = parser.parse_args() - - if args.force_conversion and args.no_conversion: - parser.error("--force_conversion and --no-conversion are mutually exclusive.") - - return args - - -def _bootstrap_logging(verbosity: int = 0) -> None: - """Configure Python's logger according to the given verbosity level. - - :param verbosity: The desired verbosity level. Must be one of 0, 1, or 2. - :type verbosity: typing.Literal[0, 1, 2] - """ - # determine log level - verbosity = min(2, max(0, verbosity)) # limit verbosity to 0-2 - log_level = [logging.WARN, logging.INFO, logging.DEBUG][verbosity] - - # configure python's logger - logging.basicConfig(format=_LOG_FMT, datefmt=_LOG_DATE_FMT, level=log_level) - # update existing loggers - _LOGGER.setLevel(log_level) - # pylint: disable-next=no-member; false positive - for logger_name in logging.root.manager.loggerDict: - logger = logging.getLogger(logger_name) - for handler in logger.handlers: - handler.setFormatter(logging.Formatter(fmt=_LOG_FMT, datefmt=_LOG_DATE_FMT)) - - -def _k8s_error_handler(err: Exception) -> None: - """When running in Kubernetes, write errors to the termination log.""" - with open(TERMINATION_LOG, "w", encoding="UTF-8") as term_log: - # recursively write nested exceptions - def _write_errors_to_term_log(e: BaseException) -> None: - term_log.write(f"{type(e)}: {e}\n") - if e.__cause__: - _write_errors_to_term_log(e.__cause__) - - _write_errors_to_term_log(err) - - -def _error_handler(err: Exception) -> int: - """Catch and handle exceptions from the applicaiton.""" - # keybaord interrupts are fine - if isinstance(err, KeyboardInterrupt): - return 0 - - # on k8s, write errors to log file - if os.path.isfile(TERMINATION_LOG): - _k8s_error_handler(err) - - # raise uncaught errors - if not isinstance(err, ModelServerException): - raise err - - # gracefully handle caught errors - _LOGGER.error(str(err)) - - # if there is a nested error, raise it - if err.__cause__: - raise err.__cause__ - - # we decided to quite gracefully - return 1 - - -if __name__ == "__main__": - try: - _ARGS = parse_args() - _bootstrap_logging(_ARGS.verbose - _ARGS.quiet) - sys.exit(main(_ARGS)) - # pylint: disable-next=broad-exception-caught; Error handling based on type is done in the handler - except Exception as _ERR: - sys.exit(_error_handler(_ERR)) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/__init__.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/__init__.py deleted file mode 100644 index f729920bd..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module contains the logic for doing model conversions to TensorRT.""" -from dataclasses import dataclass -from typing import Optional - -from ..errors import ModelServerException -from ..model import Model, ModelFormats, ModelTypes - - -@dataclass -class ConversionOptions: - """Class containing the options used in TRT conversion.""" - - max_input_length: int - max_output_length: int - pipline_parallelism: int - tensor_parallelism: int - vocab_size: Optional[int] = None - quantization: Optional[str] = "" - - -def convert(model: Model, opts: ConversionOptions) -> None: - """ - Convert the provided model to TensorRT. - - Supported types and formats: - +----------+---------+---------+---------+---------+---------+ - | | NEMO | PYTORCH | ONNX | HFACE | UNKNOWN | - +----------+---------+---------+---------+---------+---------+ - | LLAMA | ✅ | ✅ | ❌ | ✅ | ❌ | - | GPTNEXT | ✅ | ❌ | ❌ | ❌ | ❌ | - +----------+---------+---------+---------+---------+---------+ - """ - if model.format == ModelFormats.NEMO: - # pylint: disable-next=import-outside-toplevel # preventing circular imports - from . import nemo - - nemo.convert(model, opts) - - elif model.type == ModelTypes.LLAMA: - # pylint: disable-next=import-outside-toplevel # preventing circular imports - from . import llama - - opts.vocab_size = 32000 - llama.convert(model, opts) - - elif model.type == ModelTypes.CODE_LLAMA: - # pylint: disable-next=import-outside-toplevel # preventing circular imports - from . import llama - - opts.vocab_size = 32016 - llama.convert(model, opts) - - else: - supported_types = [e.name for e in ModelTypes] - raise ModelServerException( - f"Unsupported model type. Conversion is supported for the following types: {supported_types}" - ) - - model.write_hash() diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/llama.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/llama.py deleted file mode 100644 index 60b93c667..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/llama.py +++ /dev/null @@ -1,127 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module contains the logic for exporting a Llama model in PyTorch format to TensorRT.""" -import logging -import os -import subprocess -import sys -import typing - -from ..errors import ModelServerException, UnsupportedFormatException -from ..model import Model -from . import ConversionOptions - -_CONVERSION_SCRIPTS = "/opt/conversion_scripts/llama" - -_CHECKPOINT_ARGS_FLAGS = {"PYTORCH": "--meta_ckpt_dir", "HUGGINGFACE": "--model_dir"} -_QUANTIZATIONS = ["int4_awq"] - -_LOGGER = logging.getLogger(__name__) - -def find_pt_file(directory): - for root, dirs, files in os.walk(directory): - for file in files: - if file.endswith(".pt"): - return os.path.join(root, file) - return None - -def convert(model: Model, opts: ConversionOptions) -> None: - """Convert a llama model.""" - _LOGGER.debug("Running Llama model conversion.") - _LOGGER.info(f"Model Format: {model.format.name}") - - # construct builder executable path - cwd = _CONVERSION_SCRIPTS - exe = [sys.executable, "build.py"] - - # construct builder env variables - env = os.environ - - # construct builder arguments - try: - raw_args: typing.List[str] = [ - "--max_input_len", - str(opts.max_input_length), - "--max_output_len", - str(opts.max_output_length), - "--dtype", - "float16", - "--use_gpt_attention_plugin", - "float16", - "--use_inflight_batching", - "--paged_kv_cache", - "--remove_input_padding", - "--use_gemm_plugin", - "float16", - "--output_dir", - model.engine_dir, - "--world_size", - str(model.world_size), - "--tp_size", - str(opts.tensor_parallelism), - "--pp_size", - str(opts.pipline_parallelism), - "--vocab_size", - str(opts.vocab_size), - ] - - if opts.quantization: - if opts.quantization == "int4_awq" and model.format.name == "PYTORCH": - ckpt_dir = find_pt_file(model.model_dir) - raw_args.extend([ - "--use_weight_only", - "--weight_only_precision", - "int4_awq", - "--per_group", - "--quant_ckpt_path", - str(ckpt_dir), - ]) - else: - raise Exception( - "Unsupported quantization or model format, " \ - + f"supported quantizations: {_QUANTIZATIONS}, " \ - + "with format: PYTORCH" - ) - else: - raw_args.extend([ - _CHECKPOINT_ARGS_FLAGS[model.format.name], - model.model_dir, - ]) - - except KeyError as err: - raise UnsupportedFormatException( - model.format.name, ["PyTorch", "Hugging Face"] - ) from err - - # start the builder - _LOGGER.debug( - "Starting Llama exporter with the command: %s", " ".join(exe + raw_args) - ) - _LOGGER.debug("Starting Llama exporter with the env vars: %s", repr(env)) - with subprocess.Popen(exe + raw_args, env=env, cwd=cwd) as proc: - try: - retcode = proc.wait() - except KeyboardInterrupt: - proc.kill() - except Exception as err: - raise ModelServerException( - "Error running TensorRT model conversion." - ) from err - else: - if retcode != 0: - raise ModelServerException( - "TensorRT conversion returned a non-zero exit code." - ) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/nemo.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/nemo.py deleted file mode 100644 index 437f30751..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/conversion/nemo.py +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module contains the code for converting any .nemo formatted model to TRT LLM.""" -import logging -import os -from glob import glob -from tarfile import TarFile -from typing import IO, cast - -import yaml - -# pylint: disable-next=import-error -from nemo.export import TensorRTLLM # type: ignore - -from ..errors import ModelServerException -from ..model import Model -from . import ConversionOptions - -_LOGGER = logging.getLogger(__name__) - - -def convert(model: Model, opts: ConversionOptions) -> None: - """Convert a .nemo formatted model.""" - # find the .nemo model file - model_files = glob(os.path.join(model.model_dir, "*.nemo")) - if len(model_files) > 1: - raise ModelServerException( - "More than one NeMo checkpoint found in the model directory. " - + "Please only include one NeMo checkpoint file." - ) - - # verify that the model parallelism matchines the - config = {} - with TarFile(model_files[0], "r") as archive: - try: - config_file = cast(IO[bytes], archive.extractfile("./model_config.yaml")) - except KeyError: - config_file = cast(IO[bytes], archive.extractfile("model_config.yaml")) - config = yaml.safe_load(config_file) - config_file.close() - - # run the nemo to trt llm conversion - trt_llm_exporter = TensorRTLLM(model_dir=model.engine_dir) - _LOGGER.info(".nemo to TensorRT Conversion started. This will take a few minutes.") - _LOGGER.info(model.engine_dir) - trt_llm_exporter.export( - nemo_checkpoint_path=model_files[0], - model_type=model.family, - n_gpus=model.world_size, - max_input_token=opts.max_input_length, - max_output_token=opts.max_output_length - ) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/errors.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/errors.py deleted file mode 100644 index 5609a58a9..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/errors.py +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""The custom errors raised by the model server.""" -import typing - - -class ModelServerException(Exception): - """The base class for any custom expections.""" - - -class UnsupportedFormatException(ModelServerException): - """An error that indicates the model format is not supported for the provided type.""" - - def __init__(self, model_type: str, supported: typing.List[str]): - """Initialize the exception.""" - super().__init__( - "Unsupported model type and format combination. " - + f"{model_type} models are supported in the following formats: {str(supported)}" - ) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/model.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/model.py deleted file mode 100644 index 0f83459ba..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/model.py +++ /dev/null @@ -1,246 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module contains the model class that represents the model mounted to the container.""" -import glob -import hashlib -import logging -import os -import pathlib -import subprocess -import typing -from enum import Enum, auto, unique - -from .errors import ModelServerException - -DEFAULT_MODEL_DIR = "/model" -HASH_COMMAND = "sha1sum" -_LOGGER = logging.getLogger(__name__) - - -def _fast_hash_dir(dir_path: str) -> str: - """ - Read the files in a directory and quickly create a hash. - - This hash IS NOT cryptographically secure, but it is designed to be computed as quickly as reasonably possible. - This function will only hash top level files and will not traverse directories. - """ - # create a threaded pool of workers to calculate individual hases - workers = [] - for obj in os.listdir(dir_path): - obj_path = os.path.join(dir_path, obj) - if not os.path.isfile(obj_path): - continue - - workers += [ - # pylint: disable-next=consider-using-with - subprocess.Popen( - [HASH_COMMAND, obj_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - ] - - # wait for workers to complete - all_shas = b"" - for proc in workers: - stdout, _ = proc.communicate() - all_shas += stdout.split(b" ", maxsplit=1)[0] - - hasher = hashlib.sha1(usedforsecurity=False) - hasher.update(all_shas) - return hasher.hexdigest() - - -@unique -class ModelFormats(Enum): - """A Enumerator containing all of the supported model types.""" - - UNKNOWN = auto() - ONNX = auto() - PYTORCH = auto() - HUGGINGFACE = auto() - NEMO = auto() - - -@unique -class ModelTypes(Enum): - """A enumerator of the supported model types.""" - - LLAMA = auto() - CODE_LLAMA = auto() - GPTNEXT = auto() - - @property - def family(self) -> str: - """Return the family grouping of the model.""" - return ["llama", "llama", "gptnext"][self.value - 1] - - -class Model: - """A representation of the mounted model.""" - - def __init__( - self, - model_type: str, - model_dir: typing.Optional[str] = None, - world_size: typing.Optional[int] = None, - ): - """Initialize the model class.""" - try: - self._type = ModelTypes[model_type.upper().replace("-", "_")] - except KeyError as err: - raise ModelServerException(f"Unrecognized model type {type}") from err - - self._model_dir = model_dir or DEFAULT_MODEL_DIR - self._gpu_info = self._init_gpu_info(world_size=world_size) - self._hash: typing.Optional[str] = None - self._engine_dir = self._init_engine_dir() - self._format = self._init_model_format() - - @classmethod - def _init_gpu_info( - cls, - world_size: typing.Optional[int] = None, - ) -> typing.Dict[str, typing.Union[str, int]]: - """ - Get the product name and architecture for the first GPU in the system. - - Returns - ------- - Tuple: A tuple of the product name and architecture. - """ - query_cmd = ["nvidia-smi", "--query-gpu=compute_cap", "--format=csv,noheader"] - gpu_info_raw = subprocess.check_output(query_cmd) - compute_caps = [cap.decode() for cap in gpu_info_raw.strip().split(b"\n")] - # FUTURE: convert this to use nvml instead - - # do basic error checking - if len(compute_caps) == 0: - raise ModelServerException("No GPUs attached to the container.") - if len(set(compute_caps)) > 1: - raise ModelServerException( - "Attached GPUs are dissimilar. All GPUs must be of the same type." - ) - if not world_size: - world_size = len(compute_caps) - - return {"compute_cap": compute_caps[0], "world_size": world_size} - - def _init_engine_dir(self) -> str: - """Create and return the path to the TensorRT cache directory for this model.""" - cache_dir = f"trt-w{self.world_size}-cc{self.compute_cap}" - cache_path = os.path.join(self.model_dir, cache_dir) - pathlib.Path(cache_path).mkdir(parents=True, exist_ok=True) - return cache_path - - def _init_model_format(self) -> ModelFormats: - """Determine the format of model that has been mounted.""" - # look for nemo checkpoints - nemo_count = self._file_ext_count("nemo") - if nemo_count == 1: - return ModelFormats.NEMO - if nemo_count > 1: - raise ModelServerException( - f"Only one nemo checkpoint file may be in the model directory. Found {nemo_count}", - ) - - # look for pytorch saved models - pytorch_count = self._file_ext_count("pth") + self._file_ext_count("pt") - if pytorch_count: - return ModelFormats.PYTORCH - - # look for huggingface saved models - hf_count = self._file_ext_count("bin") - if hf_count: - return ModelFormats.HUGGINGFACE - - # look for onnx models - onnx_count = self._file_ext_count("onnx") - if onnx_count: - return ModelFormats.ONNX - - return ModelFormats.UNKNOWN - - def _file_ext_count(self, extension: str) -> int: - """Count the files in a directory with a given extension.""" - path = os.path.join(self.model_dir, f"*.{extension}") - return len(glob.glob(path)) - - @property - def type(self) -> ModelTypes: - """Return the type of the model.""" - return self._type - - @property - def family(self) -> str: - """Return the model family grouping.""" - return self._type.family - - @property - def model_dir(self) -> str: - """Return the stored model directory.""" - return self._model_dir - - @property - def engine_dir(self) -> str: - """Return the stored engine directory.""" - return self._engine_dir - - @property - def world_size(self) -> int: - """Return the world size.""" - ws = self._gpu_info["world_size"] - return typing.cast(int, ws) - - @property - def compute_cap(self) -> str: - """Return the compute capability version.""" - cc = self._gpu_info["compute_cap"] - return typing.cast(str, cc) - - @property - def format(self) -> ModelFormats: - """Return the format of the model.""" - return self._format - - @property - def hash(self) -> str: - """Return the hash of the model.""" - if not self._hash: - _LOGGER.info("Calculating model hash.") - self._hash = _fast_hash_dir(self.model_dir) - return self._hash - - @property - def _last_hash_path(self) -> str: - """Return the path to the last known hash file.""" - return os.path.join(self.engine_dir, "hash") - - def conversion_is_needed(self) -> bool: - """Determine if the engine conversion is required.""" - if not os.path.isfile(self._last_hash_path): - _LOGGER.debug("No engine file exists. Will generate an engine file.") - return True - with open(self._last_hash_path, "r", encoding="ASCII") as hash_file: - last_hash = hash_file.read() - if last_hash != self.hash: - _LOGGER.debug("Change in model hash detected. Will regnerate engine file.") - return True - _LOGGER.debug("Existing engine file found.") - return False - - def write_hash(self) -> None: - """Write the model hash to the engine directory.""" - with open(self._last_hash_path, "w", encoding="ASCII") as hash_file: - hash_file.write(self.hash) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server/server.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server/server.py deleted file mode 100644 index 272234ec5..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server/server.py +++ /dev/null @@ -1,155 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module contains the code to statup triton inference servers.""" -import logging -import os -import subprocess -import typing - -from jinja2 import Environment, FileSystemLoader - -from .model import Model, ModelFormats - -_ENSEMBLE_MODEL_DIR = "/opt/ensemble_models" -_TRITON_BIN = "/opt/tritonserver/bin/tritonserver" -_MPIRUN_BIN = "/usr/local/mpi/bin/mpirun" -_LOGGER = logging.getLogger(__name__) - - -class ModelServer: - """Abstraction of a multi-gpu triton inference server cluster.""" - - def __init__(self, model: Model, http: bool = False) -> None: - """Initialize the model server.""" - self._model = model - self._http = http - - @property - def _decoupled_mode(self) -> str: - """Indicate if the Triton models should be hosted in decoupled mode for streaming.""" - if self._model.format == ModelFormats.NEMO: - return "false" - return "true" if not self._http else "false" - - @property - def _allow_http(self) -> str: - """Indicate if Triton should allow http connections.""" - if self._model.format == ModelFormats.NEMO: - return "true" - return "true" if self._http else "false" - - @property - def _allow_grpc(self) -> str: - """Inidicate if Triton should allow grpc connections.""" - return "true" if not self._http else "false" - - @property - def _tokenizer_model_dir(self) -> str: - """Inidicate where the tokenizer model can be found.""" - if self._model.format == ModelFormats.NEMO: - return self._model.engine_dir - return self._model.model_dir - - @property - def _gpt_model_type(self) -> str: - """Indicate the TRT LLM Backend mode.""" - if self._model.format == ModelFormats.NEMO: - return "V1" - return "inflight_fused_batching" - - @property - def model_repository(self) -> str: - """Return the triton model repository.""" - return os.path.join(_ENSEMBLE_MODEL_DIR, self._model.family) - - def _triton_server_cmd(self, rank: int) -> typing.List[str]: - """Generate the command to start a single triton server of given rank.""" - return [ - "-n", - "1", - _TRITON_BIN, - "--allow-http", - self._allow_http, - "--allow-grpc", - self._allow_grpc, - "--model-repository", - self.model_repository, - "--disable-auto-complete-config", - f"--backend-config=python,shm-region-prefix-name=prefix{rank}_", - ":", - ] - - @property - def _cmd(self) -> typing.List[str]: - """Generate the full command.""" - cmd = [_MPIRUN_BIN] - for rank in range(self._model.world_size): - cmd += self._triton_server_cmd(rank) - return cmd - - @property - def _env(self) -> typing.Dict[str, str]: - """Return the environment variable for the triton inference server.""" - env = dict(os.environ) - env["TRT_ENGINE_DIR"] = self._model.engine_dir - env["TOKENIZER_DIR"] = self._tokenizer_model_dir - if os.getuid() == 0: - _LOGGER.warning( - "Triton server will be running as root. It is recommended that you don't run this container as root." - ) - env["OMPI_ALLOW_RUN_AS_ROOT"] = "1" - env["OMPI_ALLOW_RUN_AS_ROOT_CONFIRM"] = "1" - return env - - def _render_model_templates(self) -> None: - """Render and Jinja templates in the model directory.""" - env = Environment( - loader=FileSystemLoader(searchpath=self.model_repository), - autoescape=False, - ) # nosec; all the provided values are from code, not the user - - template_path = os.path.join("tensorrt_llm", "config.pbtxt.j2") - output_path = os.path.join( - self.model_repository, "tensorrt_llm", "config.pbtxt" - ) - - template = env.get_template(template_path) - - with open(output_path, "w", encoding="UTF-8") as out: - template_args = { - "engine_dir": self._model.engine_dir, - "decoupled_mode": self._decoupled_mode, - "gpt_model_type": self._gpt_model_type, - } - out.write(template.render(**template_args)) - - def run(self) -> int: - """Start the triton inference server.""" - cmd = self._cmd - env = self._env - - _LOGGER.debug("Rendering the ensemble models.") - self._render_model_templates() - - _LOGGER.debug("Starting triton with the command: %s", " ".join(cmd)) - _LOGGER.debug("Starting triton with the env vars: %s", repr(env)) - with subprocess.Popen(cmd, env=env) as proc: - try: - retcode = proc.wait() - except KeyboardInterrupt: - proc.kill() - return 0 - return retcode diff --git a/RetrievalAugmentedGeneration/llm-inference-server/model_server_client/trt_llm.py b/RetrievalAugmentedGeneration/llm-inference-server/model_server_client/trt_llm.py deleted file mode 100644 index 7291db4c1..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/model_server_client/trt_llm.py +++ /dev/null @@ -1,544 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A Langchain LLM component for connecting to Triton + TensorRT LLM backend.""" -# pylint: disable=too-many-lines -import abc -import json -import queue -import random -import time -from functools import partial -from typing import Any, Callable, Dict, List, Optional, Type, Union - -import google.protobuf.json_format -import numpy as np -import tritonclient.grpc as grpcclient -import tritonclient.http as httpclient -from tritonclient.grpc.service_pb2 import ModelInferResponse -from tritonclient.utils import np_to_triton_dtype - -try: - from langchain.callbacks.manager import CallbackManagerForLLMRun - from langchain.llms.base import LLM - from langchain.pydantic_v1 import Field, root_validator - - USE_LANGCHAIN = True -except ImportError: - USE_LANGCHAIN = False - - -STOP_WORDS = [""] -RANDOM_SEED = 0 - -if USE_LANGCHAIN: - # pylint: disable-next=too-few-public-methods # Interface is defined by LangChain - class TensorRTLLM(LLM): # type: ignore # LLM class not typed in langchain - """A custom Langchain LLM class that integrates with TRTLLM triton models. - - Arguments: - server_url: (str) The URL of the Triton inference server to use. - model_name: (str) The name of the Triton TRT model to use. - temperature: (str) Temperature to use for sampling - top_p: (float) The top-p value to use for sampling - top_k: (float) The top k values use for sampling - beam_width: (int) Last n number of tokens to penalize - repetition_penalty: (int) Last n number of tokens to penalize - length_penalty: (float) The penalty to apply repeated tokens - tokens: (int) The maximum number of tokens to generate. - client: The client object used to communicate with the inference server - """ - - server_url: str = Field(None, alias="server_url") - - # # all the optional arguments - model_name: str = "ensemble" - temperature: Optional[float] = 1.0 - top_p: Optional[float] = 0 - top_k: Optional[int] = 1 - tokens: Optional[int] = 100 - beam_width: Optional[int] = 1 - repetition_penalty: Optional[float] = 1.0 - length_penalty: Optional[float] = 1.0 - client: Any - streaming: Optional[bool] = True - - @root_validator() # type: ignore # typing not declared in langchain - @classmethod - def validate_environment(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Validate that python package exists in environment.""" - try: - if values.get("streaming", True): - values["client"] = GrpcTritonClient(values["server_url"]) - else: - values["client"] = HttpTritonClient(values["server_url"]) - - except ImportError as err: - raise ImportError( - "Could not import triton client python package. " - "Please install it with `pip install tritonclient[all]`." - ) from err - return values - - @property - def _get_model_default_parameters(self) -> Dict[str, Any]: - return { - "tokens": self.tokens, - "top_k": self.top_k, - "top_p": self.top_p, - "temperature": self.temperature, - "repetition_penalty": self.repetition_penalty, - "length_penalty": self.length_penalty, - "beam_width": self.beam_width, - } - - @property - def _invocation_params(self, **kwargs: Any) -> Dict[str, Any]: - params = {**self._get_model_default_parameters, **kwargs} - return params - - @property - def _identifying_params(self) -> Dict[str, Any]: - """Get all the identifying parameters.""" - return { - "server_url": self.server_url, - "model_name": self.model_name, - } - - @property - def _llm_type(self) -> str: - return "triton_tensorrt" - - def _call( - self, - prompt: str, - stop: Optional[List[str]] = None, # pylint: disable=unused-argument - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> str: - """ - Execute an inference request. - - Args: - prompt: The prompt to pass into the model. - stop: A list of strings to stop generation when encountered - - Returns: - The string generated by the model - """ - text_callback = None - if run_manager: - text_callback = partial( - run_manager.on_llm_new_token, verbose=self.verbose - ) - - invocation_params = self._get_model_default_parameters - invocation_params.update(kwargs) - invocation_params["prompt"] = [[prompt]] - model_params = self._identifying_params - model_params.update(kwargs) - request_id = str(random.randint(1, 9999999)) # nosec - - self.client.load_model(model_params["model_name"]) - if isinstance(self.client, GrpcTritonClient): - return self._streaming_request( - model_params, request_id, invocation_params, text_callback - ) - return self._request(model_params, invocation_params, text_callback) - - def _streaming_request( - self, - model_params: Dict[str, Any], - request_id: str, - invocation_params: Dict[str, Any], - text_callback: Optional[Callable[[str], None]], - ) -> str: - """Request a streaming inference session.""" - result_queue = self.client.request_streaming( - model_params["model_name"], request_id, **invocation_params - ) - - response = "" - for token in result_queue: - if text_callback: - text_callback(token) - response = response + token - return response - - def _request( - self, - model_params: Dict[str, Any], - invocation_params: Dict[str, Any], - text_callback: Optional[Callable[[str], None]], - ) -> str: - """Request a streaming inference session.""" - token: str = self.client.request( - model_params["model_name"], **invocation_params - ) - if text_callback: - text_callback(token) - return token - - -class StreamingResponseGenerator(queue.Queue[Optional[str]]): - """A Generator that provides the inference results from an LLM.""" - - def __init__( - self, client: "GrpcTritonClient", request_id: str, force_batch: bool - ) -> None: - """Instantiate the generator class.""" - super().__init__() - self._client = client - self.request_id = request_id - self._batch = force_batch - - def __iter__(self) -> "StreamingResponseGenerator": - """Return self as a generator.""" - return self - - def __next__(self) -> str: - """Return the next retrieved token.""" - val = self.get() - if val is None or val in STOP_WORDS: - self._stop_stream() - raise StopIteration() - return val - - def _stop_stream(self) -> None: - """Drain and shutdown the Triton stream.""" - self._client.stop_stream( - "tensorrt_llm", self.request_id, signal=not self._batch - ) - - -class _BaseTritonClient(abc.ABC): - """An abstraction of the connection to a triton inference server.""" - - def __init__(self, server_url: str) -> None: - """Initialize the client.""" - self._server_url = server_url - self._client = self._inference_server_client(server_url) - - @property - @abc.abstractmethod - def _inference_server_client( - self, - ) -> Union[ - Type[grpcclient.InferenceServerClient], Type[httpclient.InferenceServerClient] - ]: - """Return the prefered InferenceServerClient class.""" - - @property - @abc.abstractmethod - def _infer_input( - self, - ) -> Union[Type[grpcclient.InferInput], Type[httpclient.InferInput]]: - """Return the preferred InferInput.""" - - @property - @abc.abstractmethod - def _infer_output( - self, - ) -> Union[ - Type[grpcclient.InferRequestedOutput], Type[httpclient.InferRequestedOutput] - ]: - """Return the preferred InferRequestedOutput.""" - - def load_model(self, model_name: str, timeout: int = 1000) -> None: - """Load a model into the server.""" - if self._client.is_model_ready(model_name): - return - - self._client.load_model(model_name) - t0 = time.perf_counter() - t1 = t0 - while not self._client.is_model_ready(model_name) and t1 - t0 < timeout: - t1 = time.perf_counter() - - if not self._client.is_model_ready(model_name): - raise RuntimeError(f"Failed to load {model_name} on Triton in {timeout}s") - - def get_model_list(self) -> List[str]: - """Get a list of models loaded in the triton server.""" - res = self._client.get_model_repository_index(as_json=True) - return [model["name"] for model in res["models"]] - - def get_model_concurrency(self, model_name: str, timeout: int = 1000) -> int: - """Get the modle concurrency.""" - self.load_model(model_name, timeout) - instances = self._client.get_model_config(model_name, as_json=True)["config"][ - "instance_group" - ] - return sum(instance["count"] * len(instance["gpus"]) for instance in instances) - - def _generate_stop_signals( - self, - ) -> List[Union[grpcclient.InferInput, httpclient.InferInput]]: - """Generate the signal to stop the stream.""" - inputs = [ - self._infer_input("input_ids", [1, 1], "INT32"), - self._infer_input("input_lengths", [1, 1], "INT32"), - self._infer_input("request_output_len", [1, 1], "UINT32"), - self._infer_input("stop", [1, 1], "BOOL"), - ] - inputs[0].set_data_from_numpy(np.empty([1, 1], dtype=np.int32)) - inputs[1].set_data_from_numpy(np.zeros([1, 1], dtype=np.int32)) - inputs[2].set_data_from_numpy(np.array([[0]], dtype=np.uint32)) - inputs[3].set_data_from_numpy(np.array([[True]], dtype="bool")) - return inputs - - def _generate_outputs( - self, - ) -> List[Union[grpcclient.InferRequestedOutput, httpclient.InferRequestedOutput]]: - """Generate the expected output structure.""" - return [self._infer_output("text_output")] - - def _prepare_tensor( - self, name: str, input_data: Any - ) -> Union[grpcclient.InferInput, httpclient.InferInput]: - """Prepare an input data structure.""" - t = self._infer_input( - name, input_data.shape, np_to_triton_dtype(input_data.dtype) - ) - t.set_data_from_numpy(input_data) - return t - - def _generate_inputs( # pylint: disable=too-many-arguments,too-many-locals - self, - prompt: str, - tokens: int = 300, - temperature: float = 1.0, - top_k: float = 1, - top_p: float = 0, - beam_width: int = 1, - repetition_penalty: float = 1, - length_penalty: float = 1.0, - stream: bool = True, - ) -> List[Union[grpcclient.InferInput, httpclient.InferInput]]: - """Create the input for the triton inference server.""" - query = np.array(prompt).astype(object) - request_output_len = np.array([tokens]).astype(np.uint32).reshape((1, -1)) - runtime_top_k = np.array([top_k]).astype(np.uint32).reshape((1, -1)) - runtime_top_p = np.array([top_p]).astype(np.float32).reshape((1, -1)) - temperature_array = np.array([temperature]).astype(np.float32).reshape((1, -1)) - len_penalty = np.array([length_penalty]).astype(np.float32).reshape((1, -1)) - repetition_penalty_array = ( - np.array([repetition_penalty]).astype(np.float32).reshape((1, -1)) - ) - random_seed = np.array([RANDOM_SEED]).astype(np.uint64).reshape((1, -1)) - beam_width_array = np.array([beam_width]).astype(np.uint32).reshape((1, -1)) - streaming_data = np.array([[stream]], dtype=bool) - - inputs = [ - self._prepare_tensor("text_input", query), - self._prepare_tensor("max_tokens", request_output_len), - self._prepare_tensor("top_k", runtime_top_k), - self._prepare_tensor("top_p", runtime_top_p), - self._prepare_tensor("temperature", temperature_array), - self._prepare_tensor("length_penalty", len_penalty), - self._prepare_tensor("repetition_penalty", repetition_penalty_array), - self._prepare_tensor("random_seed", random_seed), - self._prepare_tensor("beam_width", beam_width_array), - self._prepare_tensor("stream", streaming_data), - ] - return inputs - - def _trim_batch_response(self, result_str: str) -> str: - """Trim the resulting response from a batch request by removing provided prompt and extra generated text.""" - # extract the generated part of the prompt - split = result_str.split("[/INST]", 1) - generated = split[-1] - end_token = generated.find("") - if end_token == -1: - return generated - generated = generated[:end_token].strip() - return generated - - -class GrpcTritonClient(_BaseTritonClient): - """GRPC connection to a triton inference server.""" - - @property - def _inference_server_client( - self, - ) -> Type[grpcclient.InferenceServerClient]: - """Return the prefered InferenceServerClient class.""" - return grpcclient.InferenceServerClient # type: ignore - - @property - def _infer_input(self) -> Type[grpcclient.InferInput]: - """Return the preferred InferInput.""" - return grpcclient.InferInput # type: ignore - - @property - def _infer_output( - self, - ) -> Type[grpcclient.InferRequestedOutput]: - """Return the preferred InferRequestedOutput.""" - return grpcclient.InferRequestedOutput # type: ignore - - def _send_stop_signals(self, model_name: str, request_id: str) -> None: - """Send the stop signal to the Triton Inference server.""" - stop_inputs = self._generate_stop_signals() - self._client.async_stream_infer( - model_name, - stop_inputs, - request_id=request_id, - parameters={"Streaming": True}, - ) - - @staticmethod - def _process_result(result: Dict[str, str]) -> str: - """Post-process the result from the server.""" - message = ModelInferResponse() - generated_text: str = "" - google.protobuf.json_format.Parse(json.dumps(result), message) - infer_result = grpcclient.InferResult(message) - np_res = infer_result.as_numpy("text_output") - - generated_text = "" - if np_res is not None: - generated_text = "".join([token.decode() for token in np_res]) - - return generated_text - - def _stream_callback( - self, - result_queue: queue.Queue[Union[Optional[Dict[str, str]], str]], - force_batch: bool, - result: Any, - error: str, - ) -> None: - """Add streamed result to queue.""" - if error: - result_queue.put(error) - else: - response_raw = result.get_response(as_json=True) - if "outputs" in response_raw: - # the very last response might have no output, just the final flag - response = self._process_result(response_raw) - if force_batch: - response = self._trim_batch_response(response) - - if response in STOP_WORDS: - result_queue.put(None) - else: - result_queue.put(response) - - if response_raw["parameters"]["triton_final_response"]["bool_param"]: - # end of the generation - result_queue.put(None) - - # pylint: disable-next=too-many-arguments - def _send_prompt_streaming( - self, - model_name: str, - request_inputs: Any, - request_outputs: Optional[Any], - request_id: str, - result_queue: StreamingResponseGenerator, - force_batch: bool = False, - ) -> None: - """Send the prompt and start streaming the result.""" - self._client.start_stream( - callback=partial(self._stream_callback, result_queue, force_batch) - ) - self._client.async_stream_infer( - model_name=model_name, - inputs=request_inputs, - outputs=request_outputs, - request_id=request_id, - ) - - def request_streaming( - self, - model_name: str, - request_id: Optional[str] = None, - force_batch: bool = False, - **params: Any, - ) -> StreamingResponseGenerator: - """Request a streaming connection.""" - if not self._client.is_model_ready(model_name): - raise RuntimeError("Cannot request streaming, model is not loaded") - - if not request_id: - request_id = str(random.randint(1, 9999999)) # nosec - - result_queue = StreamingResponseGenerator(self, request_id, force_batch) - inputs = self._generate_inputs(stream=not force_batch, **params) - outputs = self._generate_outputs() - self._send_prompt_streaming( - model_name, - inputs, - outputs, - request_id, - result_queue, - force_batch, - ) - return result_queue - - def stop_stream( - self, model_name: str, request_id: str, signal: bool = True - ) -> None: - """Close the streaming connection.""" - if signal: - self._send_stop_signals(model_name, request_id) - self._client.stop_stream() - - -class HttpTritonClient(_BaseTritonClient): - """HTTP connection to a triton inference server.""" - - @property - def _inference_server_client( - self, - ) -> Type[httpclient.InferenceServerClient]: - """Return the prefered InferenceServerClient class.""" - return httpclient.InferenceServerClient # type: ignore - - @property - def _infer_input(self) -> Type[httpclient.InferInput]: - """Return the preferred InferInput.""" - return httpclient.InferInput # type: ignore - - @property - def _infer_output( - self, - ) -> Type[httpclient.InferRequestedOutput]: - """Return the preferred InferRequestedOutput.""" - return httpclient.InferRequestedOutput # type: ignore - - def request( - self, - model_name: str, - **params: Any, - ) -> str: - """Request inferencing from the triton server.""" - if not self._client.is_model_ready(model_name): - raise RuntimeError("Cannot request streaming, model is not loaded") - - # create model inputs and outputs - inputs = self._generate_inputs(stream=False, **params) - outputs = self._generate_outputs() - - # call the model for inference - result = self._client.infer(model_name, inputs=inputs, outputs=outputs) - result_str = "".join( - [val.decode("utf-8") for val in result.as_numpy("text_output").tolist()] - ) - - # extract the generated part of the prompt - # return(result_str) - return self._trim_batch_response(result_str) diff --git a/RetrievalAugmentedGeneration/llm-inference-server/requirements.txt b/RetrievalAugmentedGeneration/llm-inference-server/requirements.txt deleted file mode 100644 index 3f6a77344..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -jinja2 -langchain -numpy -protobuf -requests -tritonclient[all] -pyyaml diff --git a/RetrievalAugmentedGeneration/llm-inference-server/tools/resize_nemo_model.sh b/RetrievalAugmentedGeneration/llm-inference-server/tools/resize_nemo_model.sh deleted file mode 100755 index fa35fe16c..000000000 --- a/RetrievalAugmentedGeneration/llm-inference-server/tools/resize_nemo_model.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -set -x - -MODEL_STORE="$1" -MODEL_IN="$2" -MODEL_IN_DIR=$(cd $(dirname "$MODEL_IN"); pwd) -MODEL_OUT="$3" -MODEL_OUT_DIR=$(cd $(dirname "$MODEL_OUT"); pwd) -TARGET_SIZE="$4" - -TRAINING_CONTAINER="nvcr.io/nvaie/nemo-framework-training:23.08.03" - -# init -echo $MODEL_IN " -> " $MODEL_OUT -cd "$MODEL_STORE" -mkdir -p "$MODEL_OUT_DIR" - -# find tokenizer -tar xvf $MODEL_IN model_config.yaml -mv model_config.yaml "$MODEL_OUT_DIR" -tokenizer=$(grep "tokenizer_model" gpt_8b_strict_skua_bf16_nemo_yi_dong_us_v1.0-tp1/model_config.yaml | awk -F: '{ - print $3 }') -tar xvf $MODEL_IN $tokenizer -mv $tokenizer $MODEL_OUT_DIR - -# run conversion -docker run --rm -it --gpus all --ipc host \ - -v $MODEL_STORE:$MODEL_STORE \ - -w $MODEL_STORE \ - $TRAINING_CONTAINER \ - /usr/bin/python3 \ - /opt/NeMo/examples/nlp/language_modeling/megatron_change_num_partitions.py \ - --model_file $MODEL_IN \ - --target_file $MODEL_OUT \ - --tensor_model_parallel_size=-1 \ - --target_tensor_model_parallel_size=$TARGET_SIZE \ - --pipeline_model_parallel_size=-1 \ - --target_pipeline_model_parallel_size=1 \ - --precision=bf16 \ - --tokenizer_model_path $MODEL_OUT_DIR/$tokenizer diff --git a/RetrievalAugmentedGeneration/requirements.txt b/RetrievalAugmentedGeneration/requirements.txt index 7f230915b..d24f72f81 100644 --- a/RetrievalAugmentedGeneration/requirements.txt +++ b/RetrievalAugmentedGeneration/requirements.txt @@ -3,8 +3,9 @@ uvicorn[standard]==0.27.1 python-multipart==0.0.9 langchain==0.1.9 unstructured[all-docs]==0.12.5 -sentence-transformers==2.5.1 +sentence-transformers==3.0.0 llama-index-core==0.10.27 +llama-index-readers-file==0.1.22 llama-index-llms-langchain==0.1.3 llama-index-embeddings-langchain==0.1.2 llama-index-vector-stores-milvus==0.1.6 @@ -17,9 +18,7 @@ asyncpg==0.29.0 psycopg2-binary==2.9.9 pgvector==0.2.5 langchain-core==0.1.29 -langchain-nvidia-ai-endpoints==0.0.11 -langchain-nvidia-trt==0.0.1rc0 -nemollm==0.3.4 +langchain-nvidia-ai-endpoints==0.1.1 opentelemetry-sdk==1.23.0 opentelemetry-api==1.23.0 opentelemetry-exporter-otlp-proto-grpc==1.23.0 diff --git a/deploy/compose/compose.env b/deploy/compose/compose.env index 929b33c6b..f7b90945b 100644 --- a/deploy/compose/compose.env +++ b/deploy/compose/compose.env @@ -1,44 +1,39 @@ -# full path to the local copy of the model weights +# Path where models will be stored # NOTE: This should be an absolute path and not relative path -export MODEL_DIRECTORY="/home/nvidia/llama2_13b_chat_hf_v1/" +export MODEL_DIRECTORY="/home/ubuntu/model-cache" -# the number of GPUs needed by nemollm inference ms to deploy the model -export NUM_GPU=1 +# GPU id which nemo embedding ms will use +# export EMBEDDING_MS_GPU_ID=0 # To control which GPU the vector database uses, specify the device ID. # export VECTORSTORE_GPU_DEVICE_ID=0 +# GPU id which ranking ms will use (Make sure it is different from the one used for nim ms) +# export RANKING_MS_GPU_ID=1 + # Fill this out if you dont have a GPU. Leave this empty if you have a local GPU export NVIDIA_API_KEY=${NVIDIA_API_KEY} -# flag to enable activation aware quantization for the LLM -# export QUANTIZATION="int4_awq" - -# the architecture of the model. eg: llama, gptnext (for nemotron use gptnext) -export MODEL_ARCHITECTURE="llama" - - -# the name of the model being used - only for displaying on rag-playground -# export MODEL_NAME="Llama-2-13b-chat-hf" - -# [OPTIONAL] the maximum number of input tokens -# export MODEL_MAX_INPUT_LENGTH=3000 - # [OPTIONAL] the number of GPUs to make available to the inference server # export INFERENCE_GPU_COUNT="all" # [OPTIONAL] the base directory inside which all persistent volumes will be created # export DOCKER_VOLUME_DIRECTORY="." -# full path to the model store directory storing the nemo embedding model -export EMBEDDING_MODEL_DIRECTORY="/home/nvidia/nv-embed-qa_v4" # name of the nemo embedding model -export EMBEDDING_MODEL_NAME="NV-Embed-QA" -export EMBEDDING_MODEL_CKPT_NAME="NV-Embed-QA-4.nemo" +# Both arctic-embed-l & NV-Embed-QA are versions of e5-large-unsupervised +export APP_EMBEDDINGS_MODELNAME="NV-Embed-QA" +export EMBEDDING_MODEL_CKPT_NAME="snowflake-arctic-embed-l" +export EMBEDDING_MODEL_PATH="https://huggingface.co/Snowflake/snowflake-arctic-embed-l" -# GPU id which nemo embedding ms will use -# export EMBEDDING_MS_GPU_ID=0 +# name of the nemo re-rank model +export RANKING_MODEL_NAME="NV-Rerank-QA-Mistral-4B" +export RANKING_MODEL_CKPT_NAME="nv-rerank-qa-mistral-4b_v2" +export RANKING_MODEL_PATH="ohlfw0olaadg/ea-participants/nv-rerank-qa-mistral-4b:2" + +# name of the nemo retriever pipeline one of ranked_hybrid or hybrid +NEMO_RETRIEVER_PIPELINE="ranked_hybrid" # parameters for PGVector, update this when using PGVector Vector store # export POSTGRES_PASSWORD=password @@ -69,3 +64,12 @@ export TTS_SAMPLE_RATE=48000 export OPENTELEMETRY_CONFIG_FILE="./configs/otel-collector-config.yaml" # the config file for Jaeger export JAEGER_CONFIG_FILE="./configs/jaeger.yaml" + +# [OPTIONAL] Set the logging level for the chain server. Possible values are NOTSET, DEBUG, INFO, WARN, ERROR, CRITICAL. +export LOGLEVEL="INFO" + +# User permissoin for containers +export DOCKER_USER=$(id -u):$(id -g) + +# Download script path, this will be mounted at runtime +export DOWNLOAD_SCRIPT=$PWD/deploy/compose/download_model.sh diff --git a/deploy/compose/docker-compose-evaluation-application.yaml b/deploy/compose/docker-compose-evaluation-application.yaml index 66ea7461e..efe4d506b 100644 --- a/deploy/compose/docker-compose-evaluation-application.yaml +++ b/deploy/compose/docker-compose-evaluation-application.yaml @@ -1,7 +1,7 @@ services: rag_evaluator: container_name: rag-evaluator - image: rag-evaluator:latest + image: rag-evaluator:${TAG:-latest} build: context: ../../ dockerfile: ./tools/evaluation/Dockerfile @@ -18,7 +18,7 @@ services: synthetic_data_generator: container_name: data-generator - image: data-generator:latest + image: data-generator:${TAG:-latest} build: context: ../../ dockerfile: ./tools/evaluation/Dockerfile diff --git a/deploy/compose/docker-compose-nemotron.yaml b/deploy/compose/docker-compose-nemotron.yaml deleted file mode 100644 index 930555f7c..000000000 --- a/deploy/compose/docker-compose-nemotron.yaml +++ /dev/null @@ -1,184 +0,0 @@ -services: - - llm: - container_name: llm-inference-server - image: llm-inference-server:latest - build: - context: ../.././RetrievalAugmentedGeneration/llm-inference-server/ - dockerfile: Dockerfile - volumes: - - ${MODEL_DIRECTORY:?please update the env file and source it before running}:/model - command: ${MODEL_ARCHITECTURE:?please update the env file and source it before running} --http --max-input-length ${MODEL_MAX_INPUT_LENGTH:-3000} ${QUANTIZATION:+--quantization $QUANTIZATION} - ports: - - "8000:8000" - - "8001:8001" - - "8002:8002" - expose: - - "8000" - - "8001" - - "8002" - shm_size: 20gb - deploy: - resources: - reservations: - devices: - - driver: nvidia - device_ids: ["0", "1"] - capabilities: [gpu] - - jupyter-server: - container_name: notebook-server - image: notebook-server:latest - build: - context: ../../ - dockerfile: ./notebooks/Dockerfile.notebooks - ports: - - "8888:8888" - expose: - - "8888" - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: 1 - capabilities: [gpu] - depends_on: - - "llm" - - etcd: - container_name: milvus-etcd - image: quay.io/coreos/etcd:v3.5.5 - environment: - - ETCD_AUTO_COMPACTION_MODE=revision - - ETCD_AUTO_COMPACTION_RETENTION=1000 - - ETCD_QUOTA_BACKEND_BYTES=4294967296 - - ETCD_SNAPSHOT_COUNT=50000 - volumes: - - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd - command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd - healthcheck: - test: ["CMD", "etcdctl", "endpoint", "health"] - interval: 30s - timeout: 20s - retries: 3 - - minio: - container_name: milvus-minio - image: minio/minio:RELEASE.2023-03-20T20-16-18Z - environment: - MINIO_ACCESS_KEY: minioadmin - MINIO_SECRET_KEY: minioadmin - ports: - - "9011:9011" - - "9010:9010" - volumes: - - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data - command: minio server /minio_data --console-address ":9011" --address ":9010" - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9010/minio/health/live"] - interval: 30s - timeout: 20s - retries: 3 - - milvus: - container_name: milvus-standalone - image: milvusdb/milvus:v2.4.0.1-gpu-beta - command: ["milvus", "run", "standalone"] - environment: - ETCD_ENDPOINTS: etcd:2379 - MINIO_ADDRESS: minio:9010 - KNOWHERE_GPU_MEM_POOL_SIZE: 2048;4096 - volumes: - - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] - interval: 30s - start_period: 90s - timeout: 20s - retries: 3 - ports: - - "19530:19530" - - "9091:9091" - depends_on: - - "etcd" - - "minio" - deploy: - resources: - reservations: - devices: - - driver: nvidia - capabilities: ["gpu"] - count: 1 - - chain-server: - container_name: chain-server - image: chain-server:latest - build: - context: ../../ - dockerfile: ./RetrievalAugmentedGeneration/Dockerfile - args: - EXAMPLE_NAME: ${RAG_EXAMPLE} - command: --port 8081 --host 0.0.0.0 - environment: - APP_VECTORSTORE_URL: "http://milvus:19530" - APP_VECTORSTORE_NAME: "milvus" - COLLECTION_NAME: ${RAG_EXAMPLE} - MILVUS_DB: ${RAG_EXAMPLE} - APP_LLM_SERVERURL: "llm:8001" - APP_LLM_MODELNAME: ensemble - APP_LLM_MODELENGINE: triton-trt-llm - OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 - OTEL_EXPORTER_OTLP_PROTOCOL: grpc - ENABLE_TRACING: false - APP_RETRIEVER_TOPK: 4 - APP_RETRIEVER_SCORETHRESHOLD: 0.25 - ports: - - "8081:8081" - expose: - - "8081" - shm_size: 5gb - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: 1 - capabilities: [gpu] - # healthcheck: - # test: ["CMD", "curl", "-f", "http://localhost:8080/"] - # interval: 30s - # timeout: 20s - # retries: 3 - depends_on: - - "milvus" - - "llm" - - rag-playground: - container_name: rag-playground - image: rag-playground:latest - build: - context: ../.././RetrievalAugmentedGeneration/frontend/ - dockerfile: Dockerfile - command: --port 8090 - environment: - APP_SERVERURL: http://chain-server - APP_SERVERPORT: 8081 - APP_MODELNAME: ${MODEL_NAME:-${MODEL_ARCHITECTURE}} - OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 - OTEL_EXPORTER_OTLP_PROTOCOL: grpc - ENABLE_TRACING: false - RIVA_API_URI: ${RIVA_API_URI:-} - RIVA_API_KEY: ${RIVA_API_KEY:-} - RIVA_FUNCTION_ID: ${RIVA_FUNCTION_ID:-} - TTS_SAMPLE_RATE: ${TTS_SAMPLE_RATE:-48000} - ports: - - "8090:8090" - expose: - - "8090" - depends_on: - - chain-server - -networks: - default: - name: nvidia-llm diff --git a/deploy/compose/docker-compose-nim-ms.yaml b/deploy/compose/docker-compose-nim-ms.yaml index a7a372718..310943fd4 100644 --- a/deploy/compose/docker-compose-nim-ms.yaml +++ b/deploy/compose/docker-compose-nim-ms.yaml @@ -1,14 +1,16 @@ services: nemollm-inference: container_name: nemollm-inference-microservice - image: nvcr.io/ohlfw0olaadg/ea-participants/nim_llm:24.02 + image: nvcr.io/nim/meta/llama3-8b-instruct:1.0.0 volumes: - - ${MODEL_DIRECTORY:?please update the env file and source it before running}:/model-store - command: nemollm_inference_ms --model ${APP_LLM_MODELNAME:-mixtral-8x7b-instruct} --openai_port 9999 --nemo_port 9998 --num_gpus=${NUM_GPU:-1} + - ${MODEL_DIRECTORY}:/opt/nim/.cache + user: ${DOCKER_USER} ports: - - "9999:9999" + - "8000:8000" expose: - - "9999" + - "8000" + environment: + NGC_API_KEY: ${NGC_API_KEY} shm_size: 20gb deploy: resources: @@ -17,17 +19,20 @@ services: - driver: nvidia count: ${INFERENCE_GPU_COUNT:-all} capabilities: [gpu] + profiles: ["llm-embedding", "nemo-retriever"] nemollm-embedding: container_name: nemo-retriever-embedding-microservice - image: nvcr.io/ohlfw0olaadg/ea-participants/nemo-retriever-embedding-microservice:24.02 + image: nvcr.io/ohlfw0olaadg/ea-participants/nemo-retriever-embedding-microservice:24.04 volumes: - - ${EMBEDDING_MODEL_DIRECTORY:?please update the env file and source it before running}:/model-checkpoint-path - command: bin/web -p 9080 -c /model-checkpoint-path/${EMBEDDING_MODEL_CKPT_NAME} -g model_config_templates/${EMBEDDING_MODEL_NAME}_template.yaml + - $MODEL_DIRECTORY:/model-checkpoint-path + - $MODEL_DIRECTORY/embedding/cache:/model-store/ + command: ["/bin/bash", "-c", "[ -f /model-store/service_config.yaml ] && bin/web -m /model-store -p 9080 || bin/web -p 9080 -c /model-checkpoint-path/${EMBEDDING_MODEL_CKPT_NAME} -g model_config_templates/${APP_EMBEDDINGS_MODELNAME}_template.yaml"] ports: - "9080:9080" expose: - "9080" + user: ${DOCKER_USER} shm_size: 8gb deploy: resources: @@ -43,6 +48,116 @@ services: timeout: 20s retries: 3 start_period: 10m + depends_on: + nemollm-embedding-download-ngc: + condition: service_completed_successfully + nemollm-embedding-download-hf: + condition: service_completed_successfully + profiles: ["llm-embedding", "nemo-retriever"] + + ranking-ms: + image: "nvcr.io/ohlfw0olaadg/ea-participants/nemo-retriever-reranking-microservice:24.04" + volumes: + - $MODEL_DIRECTORY:/model-checkpoint-path + - $MODEL_DIRECTORY/reranking/cache:/triton-model-repository/ + command: ["/bin/bash", "-c", "[ -f /triton-model-repository/service_config.yaml ] && ./bin/web -p 8080 -r /triton-model-repository || bin/web -p 8080 -c /model-checkpoint-path/${RANKING_MODEL_CKPT_NAME} -g model_config_templates/${RANKING_MODEL_NAME}_template.yaml"] + ports: + - "1976:8080" + user: ${DOCKER_USER} + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 10s + timeout: 20s + retries: 100 + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['${RANKING_MS_GPU_ID:-0}'] + capabilities: [gpu] + depends_on: + ranking-model-download-ngc: + condition: service_completed_successfully + ranking-model-download-hf: + condition: service_completed_successfully + profiles: ["nemo-retriever"] + + nemollm-embedding-download-ngc: + container_name: nemollm-embedding-download-ngc + image: nvcr.io/ohlfw0olaadg/ea-participants/ngc-cli:v3.41.2 + user: ${DOCKER_USER} + entrypoint: ["bash", "/download_script.sh"] + volumes: + - source: $MODEL_DIRECTORY + target: /model-store + type: bind + - source: $DOWNLOAD_SCRIPT + target: /download_script.sh + type: bind + environment: + NGC_CLI_API_KEY: ${NGC_API_KEY} + NGC_CLI_ORG: ${NGC_CLI_ORG} + MODEL_PATH: ${EMBEDDING_MODEL_PATH} + MODEL_DOWNLOAD_PATH: /model-store/${EMBEDDING_MODEL_CKPT_NAME} + MODEL_TYPE: "embedding" + profiles: ["llm-embedding", "nemo-retriever"] + + nemollm-embedding-download-hf: + container_name: nemollm-embedding-download-hf + image: bitnami/git:latest + user: ${DOCKER_USER} + entrypoint: ["bash", "/download_script.sh"] + volumes: + - source: $MODEL_DIRECTORY + target: /model-store + type: bind + - source: $DOWNLOAD_SCRIPT + target: /download_script.sh + type: bind + environment: + MODEL_PATH: ${EMBEDDING_MODEL_PATH} + MODEL_DOWNLOAD_PATH: /model-store/${EMBEDDING_MODEL_CKPT_NAME} + MODEL_TYPE: "embedding" + profiles: ["llm-embedding", "nemo-retriever"] + + ranking-model-download-ngc: + container_name: ranking-model-download-ngc + image: nvcr.io/ohlfw0olaadg/ea-participants/ngc-cli:v3.41.2 + user: ${DOCKER_USER} + entrypoint: ["bash", "/download_script.sh"] + volumes: + - source: $MODEL_DIRECTORY + target: /model-store + type: bind + - source: $DOWNLOAD_SCRIPT + target: /download_script.sh + type: bind + environment: + NGC_CLI_API_KEY: ${NGC_API_KEY} + NGC_CLI_ORG: ${NGC_CLI_ORG} + MODEL_PATH: ${RANKING_MODEL_PATH} + MODEL_DOWNLOAD_PATH: /model-store/${RANKING_MODEL_CKPT_NAME} + MODEL_TYPE: "reranking" + profiles: ["nemo-retriever"] + + ranking-model-download-hf: + container_name: ranking-model-download-hf + image: bitnami/git:latest + user: ${DOCKER_USER} + entrypoint: ["bash", "/download_script.sh"] + volumes: + - source: $MODEL_DIRECTORY + target: /model-store + type: bind + - source: $DOWNLOAD_SCRIPT + target: /download_script.sh + type: bind + environment: + MODEL_PATH: ${RANKING_MODEL_PATH} + MODEL_DOWNLOAD_PATH: /model-store/${RANKING_MODEL_CKPT_NAME} + MODEL_TYPE: "reranking" + profiles: ["nemo-retriever"] networks: default: diff --git a/deploy/compose/docker-compose-vectordb.yaml b/deploy/compose/docker-compose-vectordb.yaml index d26e9c590..98c625ab7 100644 --- a/deploy/compose/docker-compose-vectordb.yaml +++ b/deploy/compose/docker-compose-vectordb.yaml @@ -12,6 +12,8 @@ services: - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password} - POSTGRES_USER=${POSTGRES_USER:-postgres} - POSTGRES_DB=${POSTGRES_DB:-api} + profiles: ["llm-embedding"] + etcd: container_name: milvus-etcd @@ -29,10 +31,11 @@ services: interval: 30s timeout: 20s retries: 3 + profiles: ["llm-embedding", "nemo-retriever"] minio: container_name: milvus-minio - image: minio/minio:RELEASE.2023-03-20T20-16-18Z + image: minio/minio:RELEASE.2024-05-01T01-11-10Z environment: MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin @@ -47,10 +50,11 @@ services: interval: 30s timeout: 20s retries: 3 + profiles: ["llm-embedding", "nemo-retriever"] milvus: container_name: milvus-standalone - image: milvusdb/milvus:v2.4.0.1-gpu-beta + image: milvusdb/milvus:v2.4.4-gpu command: ["milvus", "run", "standalone"] environment: ETCD_ENDPOINTS: etcd:2379 @@ -77,6 +81,41 @@ services: - driver: nvidia capabilities: ["gpu"] device_ids: ['${VECTORSTORE_GPU_DEVICE_ID:-0}'] + profiles: ["llm-embedding", "nemo-retriever"] + + elasticsearch: + image: "docker.elastic.co/elasticsearch/elasticsearch:8.12.0" + ports: + - 9200:9200 + restart: on-failure + environment: + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m" + - xpack.security.enabled=false + - xpack.license.self_generated.type=basic + - network.host=0.0.0.0 + - cluster.routing.allocation.disk.threshold_enabled=false + hostname: elasticsearch + healthcheck: + test: ["CMD", "curl", "-s", "-f", "http://localhost:9200/_cat/health"] + interval: 10s + timeout: 1s + retries: 10 + profiles: ["nemo-retriever"] + + postgres: + image: postgres:16.1 + restart: always + environment: + POSTGRES_PASSWORD: pgadmin + volumes: + - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/postgres_data:/var/lib/postgresql/data:Z + healthcheck: + test: ["CMD-SHELL", "sh -c 'pg_isready -U postgres -d postgres'"] + interval: 10s + timeout: 3s + retries: 3 + profiles: ["nemo-retriever"] networks: default: diff --git a/deploy/compose/download_model.sh b/deploy/compose/download_model.sh new file mode 100644 index 000000000..4bb0c2064 --- /dev/null +++ b/deploy/compose/download_model.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +mkdir -p /model-store/embedding/cache +mkdir -p /model-store/reranking/cache + +mkdir -p $MODEL_DOWNLOAD_PATH +echo "Downloading model in $MODEL_DOWNLOAD_PATH $MODEL_PATH" + +if [[ "$MODEL_PATH" == *"huggingface"* ]]; then + + if command -v git &> /dev/null; then + if [[ $(find $MODEL_DOWNLOAD_PATH -name "config.json" | wc -l) -eq 0 ]]; then + echo "Downloading from hf" + GIT_CLONE_PROTECTION_ACTIVE=false git clone $MODEL_PATH $MODEL_DOWNLOAD_PATH + pushd $MODEL_DOWNLOAD_PATH + git lfs install --local + git lfs pull + fi + + fi + +else + if command -v ngc &> /dev/null; then + if [[ $(find $MODEL_DOWNLOAD_PATH -name "config.json" | wc -l) -eq 0 ]]; then + echo "Downloading from ngc" + echo ngc registry model download-version --dest /model-store $MODEL_PATH + ngc registry model download-version --dest /model-store $MODEL_PATH + fi + fi +fi diff --git a/deploy/compose/rag-app-api-catalog-text-chatbot.yaml b/deploy/compose/rag-app-api-catalog-text-chatbot.yaml index cda076426..c0da6a6f0 100644 --- a/deploy/compose/rag-app-api-catalog-text-chatbot.yaml +++ b/deploy/compose/rag-app-api-catalog-text-chatbot.yaml @@ -1,7 +1,7 @@ services: chain-server: container_name: chain-server - image: chain-server:latest + image: chain-server:${TAG:-latest} build: context: ../../ dockerfile: ./RetrievalAugmentedGeneration/Dockerfile @@ -11,14 +11,14 @@ services: environment: APP_VECTORSTORE_URL: "http://milvus:19530" APP_VECTORSTORE_NAME: "milvus" - APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-ai-mixtral-8x7b-instruct} + APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-70b-instruct"} APP_LLM_MODELENGINE: nvidia-ai-endpoints APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-""} - APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-ai-embed-qa-4} - APP_EMBEDDINGS_MODELENGINE: nvidia-ai-endpoints + APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-snowflake/arctic-embed-l} + APP_EMBEDDINGS_MODELENGINE: ${APP_EMBEDDINGS_MODELENGINE:-nvidia-ai-endpoints} APP_EMBEDDINGS_SERVERURL: ${APP_EMBEDDINGS_SERVERURL:-""} - APP_TEXTSPLITTER_MODELNAME: WhereIsAI/UAE-Large-V1 - APP_TEXTSPLITTER_CHUNKSIZE: 510 + APP_TEXTSPLITTER_MODELNAME: Snowflake/snowflake-arctic-embed-l + APP_TEXTSPLITTER_CHUNKSIZE: 506 APP_TEXTSPLITTER_CHUNKOVERLAP: 200 NVIDIA_API_KEY: ${NVIDIA_API_KEY} APP_PROMPTS_CHATTEMPLATE: "You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Please ensure that your responses are positive in nature." @@ -26,12 +26,13 @@ services: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_DB: ${POSTGRES_DB:-api} - COLLECTION_NAME: nvidia_api_catalog + COLLECTION_NAME: ${COLLECTION_NAME:-nvidia_api_catalog} APP_RETRIEVER_TOPK: 4 APP_RETRIEVER_SCORETHRESHOLD: 0.25 OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc ENABLE_TRACING: false + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8081:8081" expose: @@ -47,7 +48,7 @@ services: rag-playground: container_name: rag-playground - image: rag-playground:latest + image: rag-playground:${TAG:-latest} build: context: ../.././RetrievalAugmentedGeneration/frontend/ dockerfile: Dockerfile @@ -55,7 +56,7 @@ services: environment: APP_SERVERURL: http://chain-server APP_SERVERPORT: 8081 - APP_MODELNAME: ${APP_LLM_MODELNAME:-ai-mixtral-8x7b-instruct} + APP_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-70b-instruct"} RIVA_API_URI: ${RIVA_API_URI:-} RIVA_API_KEY: ${RIVA_API_KEY:-} RIVA_FUNCTION_ID: ${RIVA_FUNCTION_ID:-} diff --git a/deploy/compose/rag-app-multimodal-chatbot.yaml b/deploy/compose/rag-app-multimodal-chatbot.yaml index 89bdf5f9b..cd44a7109 100644 --- a/deploy/compose/rag-app-multimodal-chatbot.yaml +++ b/deploy/compose/rag-app-multimodal-chatbot.yaml @@ -1,7 +1,7 @@ services: chain-server: container_name: chain-server - image: chain-server:latest + image: chain-server:${TAG:-latest} build: context: ../../ dockerfile: ./RetrievalAugmentedGeneration/Dockerfile @@ -9,13 +9,13 @@ services: EXAMPLE_NAME: multimodal_rag command: --port 8081 --host 0.0.0.0 environment: - APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-ai-mixtral-8x7b-instruct} + APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"} APP_LLM_MODELENGINE: nvidia-ai-endpoints APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-""} - APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-ai-embed-qa-4} - APP_EMBEDDINGS_MODELENGINE: nvidia-ai-endpoints + APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-snowflake/arctic-embed-l} + APP_EMBEDDINGS_MODELENGINE: ${APP_EMBEDDINGS_MODELENGINE:-nvidia-ai-endpoints} APP_EMBEDDINGS_SERVERURL: ${APP_EMBEDDINGS_SERVERURL:-""} - APP_TEXTSPLITTER_MODELNAME: WhereIsAI/UAE-Large-V1 + APP_TEXTSPLITTER_MODELNAME: Snowflake/snowflake-arctic-embed-l APP_TEXTSPLITTER_CHUNKSIZE: 510 APP_TEXTSPLITTER_CHUNKOVERLAP: 200 NVIDIA_API_KEY: ${NVIDIA_API_KEY} @@ -23,12 +23,13 @@ services: APP_RETRIEVER_SCORETHRESHOLD: 0.25 APP_VECTORSTORE_URL: "http://milvus:19530" APP_VECTORSTORE_NAME: "milvus" - COLLECTION_NAME: multimodal_rag + COLLECTION_NAME: ${COLLECTION_NAME:-multimodal_rag} APP_PROMPTS_CHATTEMPLATE: "You are a helpful and friendly multimodal intelligent AI assistant named Multimodal Chatbot Assistant. You are an expert in the content of the document provided and can provide information using both text and images. The user may also provide an image input, and you will use the image description to retrieve similar images, tables and text. The context given below will provide some technical or financial documentation and whitepapers to help you answer the question. Based on this context, answer the question truthfully. If the question is not related to this, please refrain from answering. Most importantly, if the context provided does not include information about the question from the user, reply saying that you don't know. Do not utilize any information that is not provided in the documents below. All documents will be preceded by tags, for example [[DOCUMENT 1]], [[DOCUMENT 2]], and so on. You can reference them in your reply but without the brackets, so just say document 1 or 2. The question will be preceded by a [[QUESTION]] tag. Be succinct, clear, and helpful. Remember to describe everything in detail by using the knowledge provided, or reply that you don't know the answer. Do not fabricate any responses. Note that you have the ability to reference images, tables, and other multimodal elements when necessary. You can also refer to the image provided by the user, if any." APP_PROMPTS_RAGTEMPLATE: "You are a helpful and friendly multimodal intelligent AI assistant named Multimodal Chatbot Assistant. You are an expert in the content of the document provided and can provide information using both text and images. The user may also provide an image input, and you will use the image description to retrieve similar images, tables and text. The context given below will provide some technical or financial documentation and whitepapers to help you answer the question. Based on this context, answer the question truthfully. If the question is not related to this, please refrain from answering. Most importantly, if the context provided does not include information about the question from the user, reply saying that you don't know. Do not utilize any information that is not provided in the documents below. All documents will be preceded by tags, for example [[DOCUMENT 1]], [[DOCUMENT 2]], and so on. You can reference them in your reply but without the brackets, so just say document 1 or 2. The question will be preceded by a [[QUESTION]] tag. Be succinct, clear, and helpful. Remember to describe everything in detail by using the knowledge provided, or reply that you don't know the answer. Do not fabricate any responses. Note that you have the ability to reference images, tables, and other multimodal elements when necessary. You can also refer to the image provided by the user, if any." OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc ENABLE_TRACING: false + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8081:8081" expose: @@ -37,7 +38,7 @@ services: rag-playground: container_name: rag-playground - image: rag-playground:latest + image: rag-playground:${TAG:-latest} build: context: ../.././RetrievalAugmentedGeneration/frontend/ dockerfile: Dockerfile @@ -45,7 +46,7 @@ services: environment: APP_SERVERURL: http://chain-server APP_SERVERPORT: 8081 - APP_MODELNAME: ${APP_LLM_MODELNAME:-ai-mixtral-8x7b-instruct} + APP_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"} RIVA_API_URI: ${RIVA_API_URI:-} RIVA_API_KEY: ${RIVA_API_KEY:-} RIVA_FUNCTION_ID: ${RIVA_FUNCTION_ID:-} diff --git a/deploy/compose/rag-app-multiturn-chatbot.yaml b/deploy/compose/rag-app-multiturn-chatbot.yaml index f6d18e2cb..c8251e876 100644 --- a/deploy/compose/rag-app-multiturn-chatbot.yaml +++ b/deploy/compose/rag-app-multiturn-chatbot.yaml @@ -1,7 +1,7 @@ services: chain-server: container_name: chain-server - image: chain-server:latest + image: chain-server:${TAG:-latest} build: context: ../../ dockerfile: ./RetrievalAugmentedGeneration/Dockerfile @@ -11,14 +11,14 @@ services: environment: APP_VECTORSTORE_URL: "http://milvus:19530" APP_VECTORSTORE_NAME: "milvus" - APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-ai-mixtral-8x7b-instruct} + APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"} APP_LLM_MODELENGINE: nvidia-ai-endpoints APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-""} - APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-ai-embed-qa-4} - APP_EMBEDDINGS_MODELENGINE: nvidia-ai-endpoints + APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-snowflake/arctic-embed-l} + APP_EMBEDDINGS_MODELENGINE: ${APP_EMBEDDINGS_MODELENGINE:-nvidia-ai-endpoints} APP_EMBEDDINGS_SERVERURL: ${APP_EMBEDDINGS_SERVERURL:-""} - APP_TEXTSPLITTER_MODELNAME: WhereIsAI/UAE-Large-V1 - APP_TEXTSPLITTER_CHUNKSIZE: 510 + APP_TEXTSPLITTER_MODELNAME: Snowflake/snowflake-arctic-embed-l + APP_TEXTSPLITTER_CHUNKSIZE: 506 APP_TEXTSPLITTER_CHUNKOVERLAP: 200 NVIDIA_API_KEY: ${NVIDIA_API_KEY} APP_RETRIEVER_TOPK: 4 @@ -26,10 +26,11 @@ services: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_DB: ${POSTGRES_DB:-api} - COLLECTION_NAME: multi_turn_rag + COLLECTION_NAME: ${COLLECTION_NAME:-multi_turn_rag} OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc ENABLE_TRACING: false + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8081:8081" expose: @@ -45,7 +46,7 @@ services: rag-playground: container_name: rag-playground - image: rag-playground:latest + image: rag-playground:${TAG:-latest} build: context: ../.././RetrievalAugmentedGeneration/frontend/ dockerfile: Dockerfile @@ -53,7 +54,7 @@ services: environment: APP_SERVERURL: http://chain-server APP_SERVERPORT: 8081 - APP_MODELNAME: ${APP_LLM_MODELNAME:-ai-mixtral-8x7b-instruct} + APP_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"} RIVA_API_URI: ${RIVA_API_URI:-} RIVA_API_KEY: ${RIVA_API_KEY:-} RIVA_FUNCTION_ID: ${RIVA_FUNCTION_ID:-} diff --git a/deploy/compose/rag-app-query-decomposition-agent.yaml b/deploy/compose/rag-app-query-decomposition-agent.yaml index 5972621d4..9bb8448bb 100644 --- a/deploy/compose/rag-app-query-decomposition-agent.yaml +++ b/deploy/compose/rag-app-query-decomposition-agent.yaml @@ -1,7 +1,7 @@ services: chain-server: container_name: chain-server - image: chain-server:latest + image: chain-server:${TAG:-latest} build: context: ../../ dockerfile: ./RetrievalAugmentedGeneration/Dockerfile @@ -11,14 +11,14 @@ services: environment: APP_VECTORSTORE_URL: "http://milvus:19530" APP_VECTORSTORE_NAME: "milvus" - APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-ai-llama2-70b} + APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-70b-instruct"} APP_LLM_MODELENGINE: nvidia-ai-endpoints APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-""} - APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-ai-embed-qa-4} - APP_EMBEDDINGS_MODELENGINE: nvidia-ai-endpoints + APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-snowflake/arctic-embed-l} + APP_EMBEDDINGS_MODELENGINE: ${APP_EMBEDDINGS_MODELENGINE:-nvidia-ai-endpoints} APP_EMBEDDINGS_SERVERURL: ${APP_EMBEDDINGS_SERVERURL:-""} - APP_TEXTSPLITTER_MODELNAME: WhereIsAI/UAE-Large-V1 - APP_TEXTSPLITTER_CHUNKSIZE: 510 + APP_TEXTSPLITTER_MODELNAME: Snowflake/snowflake-arctic-embed-l + APP_TEXTSPLITTER_CHUNKSIZE: 506 APP_TEXTSPLITTER_CHUNKOVERLAP: 200 NVIDIA_API_KEY: ${NVIDIA_API_KEY} APP_PROMPTS_CHATTEMPLATE: "You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Please ensure that your responses are positive in nature." @@ -28,10 +28,11 @@ services: POSTGRES_DB: ${POSTGRES_DB:-api} APP_RETRIEVER_TOPK: 4 APP_RETRIEVER_SCORETHRESHOLD: 0.25 - COLLECTION_NAME: query_decomposition + COLLECTION_NAME: ${COLLECTION_NAME:-query_decomposition} OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc ENABLE_TRACING: false + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8081:8081" expose: @@ -47,7 +48,7 @@ services: rag-playground: container_name: rag-playground - image: rag-playground:latest + image: rag-playground:${TAG:-latest} build: context: ../.././RetrievalAugmentedGeneration/frontend/ dockerfile: Dockerfile @@ -55,7 +56,7 @@ services: environment: APP_SERVERURL: http://chain-server APP_SERVERPORT: 8081 - APP_MODELNAME: ${APP_LLM_MODELNAME:-ai-llama2-70b} + APP_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-70b-instruct"} RIVA_API_URI: ${RIVA_API_URI:-} RIVA_API_KEY: ${RIVA_API_KEY:-} RIVA_FUNCTION_ID: ${RIVA_FUNCTION_ID:-} diff --git a/deploy/compose/rag-app-structured-data-chatbot.yaml b/deploy/compose/rag-app-structured-data-chatbot.yaml index fd95f6786..c8723d896 100644 --- a/deploy/compose/rag-app-structured-data-chatbot.yaml +++ b/deploy/compose/rag-app-structured-data-chatbot.yaml @@ -1,7 +1,7 @@ services: chain-server: container_name: chain-server - image: chain-server:latest + image: chain-server:${TAG:-latest} build: context: ../../ dockerfile: ./RetrievalAugmentedGeneration/Dockerfile @@ -9,15 +9,16 @@ services: EXAMPLE_NAME: structured_data_rag command: --port 8081 --host 0.0.0.0 environment: - APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-ai-llama3-70b} + APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-meta/llama3-70b-instruct} APP_LLM_MODELENGINE: nvidia-ai-endpoints APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-""} - APP_LLM_MODELNAMEPANDASAI: ${APP_LLM_MODELNAME:-ai-llama3-70b} + APP_LLM_MODELNAMEPANDASAI: ${APP_LLM_MODELNAME:-meta/llama3-70b-instruct} APP_PROMPTS_CHATTEMPLATE: "You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Please ensure that your responses are positive in nature." APP_PROMPTS_RAGTEMPLATE: "You are a helpful AI assistant named Envie. You will reply to questions only based on the context that you are provided. If something is out of context, you will refrain from replying and politely decline to respond to the user." NVIDIA_API_KEY: ${NVIDIA_API_KEY} - COLLECTION_NAME: structured_data_rag + COLLECTION_NAME: ${COLLECTION_NAME:-structured_data_rag} CSV_NAME: PdM_machines + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8081:8081" expose: @@ -33,7 +34,7 @@ services: rag-playground: container_name: rag-playground - image: rag-playground:latest + image: rag-playground:${TAG:-latest} build: context: ../.././RetrievalAugmentedGeneration/frontend/ dockerfile: Dockerfile @@ -41,7 +42,7 @@ services: environment: APP_SERVERURL: http://chain-server APP_SERVERPORT: 8081 - APP_MODELNAME: ${APP_LLM_MODELNAME:-ai-llama3-70b} + APP_MODELNAME: ${APP_LLM_MODELNAME:-meta/llama3-70b-instruct} RIVA_API_URI: ${RIVA_API_URI:-} RIVA_API_KEY: ${RIVA_API_KEY:-} RIVA_FUNCTION_ID: ${RIVA_FUNCTION_ID:-} diff --git a/deploy/compose/rag-app-text-chatbot.yaml b/deploy/compose/rag-app-text-chatbot.yaml index 6d5a602fb..1342367ea 100644 --- a/deploy/compose/rag-app-text-chatbot.yaml +++ b/deploy/compose/rag-app-text-chatbot.yaml @@ -1,33 +1,7 @@ services: - llm: - container_name: llm-inference-server - image: llm-inference-server:latest - build: - context: ../.././RetrievalAugmentedGeneration/llm-inference-server/ - dockerfile: Dockerfile - volumes: - - ${MODEL_DIRECTORY:?please update the env file and source it before running}:/model - command: ${MODEL_ARCHITECTURE:?please update the env file and source it before running} --max-input-length ${MODEL_MAX_INPUT_LENGTH:-3000} ${QUANTIZATION:+--quantization $QUANTIZATION} - ports: - - "8000:8000" - - "8001:8001" - - "8002:8002" - expose: - - "8000" - - "8001" - - "8002" - shm_size: 20gb - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: ${INFERENCE_GPU_COUNT:-all} - capabilities: [gpu] - jupyter-server: container_name: notebook-server - image: notebook-server:latest + image: notebook-server:${TAG:-latest} build: context: ../../ dockerfile: ./notebooks/Dockerfile.notebooks # replace GPU enabled Dockerfile ./notebooks/Dockerfile.gpu_notebook @@ -45,7 +19,7 @@ services: chain-server: container_name: chain-server - image: chain-server:latest + image: chain-server:${TAG:-latest} build: context: ../../ dockerfile: ./RetrievalAugmentedGeneration/Dockerfile @@ -55,25 +29,26 @@ services: environment: APP_VECTORSTORE_URL: "http://milvus:19530" APP_VECTORSTORE_NAME: "milvus" - APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-"llm:8001"} - APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-ensemble} - APP_LLM_MODELENGINE: ${APP_LLM_MODELENGINE:-triton-trt-llm} - APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-WhereIsAI/UAE-Large-V1} - APP_EMBEDDINGS_MODELENGINE: ${APP_EMBEDDINGS_MODELENGINE:-huggingface} + APP_EMBEDDINGS_MODELNAME: ${APP_EMBEDDINGS_MODELNAME:-snowflake/arctic-embed-l} + APP_EMBEDDINGS_MODELENGINE: ${APP_EMBEDDINGS_MODELENGINE:-nvidia-ai-endpoints} APP_EMBEDDINGS_SERVERURL: ${APP_EMBEDDINGS_SERVERURL:-""} + APP_LLM_SERVERURL: ${APP_LLM_SERVERURL:-""} + APP_LLM_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"} + APP_LLM_MODELENGINE: ${APP_LLM_MODELENGINE:-nvidia-ai-endpoints} NVIDIA_API_KEY: ${NVIDIA_API_KEY} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_DB: ${POSTGRES_DB:-api} - COLLECTION_NAME: developer_rag + COLLECTION_NAME: ${COLLECTION_NAME:-developer_rag} APP_RETRIEVER_TOPK: 4 APP_RETRIEVER_SCORETHRESHOLD: 0.25 OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc ENABLE_TRACING: false - APP_TEXTSPLITTER_MODELNAME: WhereIsAI/UAE-Large-V1 - APP_TEXTSPLITTER_CHUNKSIZE: 510 + APP_TEXTSPLITTER_MODELNAME: Snowflake/snowflake-arctic-embed-l + APP_TEXTSPLITTER_CHUNKSIZE: 506 APP_TEXTSPLITTER_CHUNKOVERLAP: 200 + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8081:8081" expose: @@ -86,12 +61,10 @@ services: - driver: nvidia count: 1 capabilities: [gpu] - depends_on: - - "llm" rag-playground: container_name: rag-playground - image: rag-playground:latest + image: rag-playground:${TAG:-latest} build: context: ../.././RetrievalAugmentedGeneration/frontend/ dockerfile: Dockerfile @@ -99,7 +72,7 @@ services: environment: APP_SERVERURL: http://chain-server APP_SERVERPORT: 8081 - APP_MODELNAME: ${MODEL_NAME:-${MODEL_ARCHITECTURE}} + APP_MODELNAME: ${APP_LLM_MODELNAME:-"meta/llama3-8b-instruct"} OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317 OTEL_EXPORTER_OTLP_PROTOCOL: grpc ENABLE_TRACING: false diff --git a/deploy/k8s-operator/kube-trailblazer/.dockerignore b/deploy/k8s-operator/kube-trailblazer/.dockerignore deleted file mode 100644 index 0f046820f..000000000 --- a/deploy/k8s-operator/kube-trailblazer/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file -# Ignore build and test binaries. -bin/ -testbin/ diff --git a/deploy/k8s-operator/kube-trailblazer/.patches/root.go b/deploy/k8s-operator/kube-trailblazer/.patches/root.go deleted file mode 100644 index fa1eb832a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/.patches/root.go +++ /dev/null @@ -1,8 +0,0 @@ -package chart - -// NotRoot not root -func (ch *Chart) NotRoot() { - ch.parent = nil - ch.dependencies = nil - ch.Metadata.Dependencies = nil -} diff --git a/deploy/k8s-operator/kube-trailblazer/Dockerfile b/deploy/k8s-operator/kube-trailblazer/Dockerfile deleted file mode 100644 index e4d416857..000000000 --- a/deploy/k8s-operator/kube-trailblazer/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -# Build the manager binary -FROM golang:1.20 as builder -ARG TARGETOS -ARG TARGETARCH - -WORKDIR /workspace -# Copy the Go Modules manifests -COPY go.mod go.mod -COPY go.sum go.sum -# cache deps before building and copying source so that we don't need to re-download as much -# and so that source changes don't invalidate our downloaded layer -#RUN go mod download -COPY vendor/ vendor/ - -# Copy the go source -COPY main.go main.go -COPY api/ api/ -COPY controllers/ controllers/ -COPY pkg/ pkg/ -COPY .kustomize/ /kustomize/ -COPY helm-charts/ helm-charts/ -COPY helm-plugins/ helm-plugins/ -COPY Makefile Makefile -COPY Makefile.helm.mk Makefile.helm.mk - -RUN chown -R 65532:65532 /kustomize - -RUN ["make", "helm-repo-index"] -# Build -# the GOARCH has not a default value to allow the binary be built according to the host where the command -# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO -# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, -# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go - -# Use distroless as minimal base image to package the manager binary -# Refer to https://github.com/GoogleContainerTools/distroless for more details -#FROM gcr.io/distroless/static:nonroot -FROM debian:bullseye-slim -#FROM ubuntu:latest -ENV HELM_PLUGINS /opt/helm-plugins - -WORKDIR / -COPY --from=builder /workspace/manager . - -COPY --from=builder --chown=65532:65532 /kustomize /kustomize -COPY --from=builder --chown=65532:65532 /workspace/build/helm-charts /helm-charts -COPY --from=builder --chown=65532:65532 /workspace/helm-plugins /opt/helm-plugins - -COPY artifacts/kustomize /usr/local/bin/kustomize - -COPY NVIDIA_AI_Product_License_1Sept2023.pdf / - -USER 65532:65532 - -ENTRYPOINT ["/manager"] diff --git a/deploy/k8s-operator/kube-trailblazer/Makefile b/deploy/k8s-operator/kube-trailblazer/Makefile deleted file mode 100644 index e09f92afd..000000000 --- a/deploy/k8s-operator/kube-trailblazer/Makefile +++ /dev/null @@ -1,282 +0,0 @@ -include *.mk -# VERSION defines the project version for the bundle. -# Update this value when you upgrade the version of your project. -# To re-generate a bundle for another specific version without changing the standard setup, you can: -# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) -# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= 0.0.1 - -# CHANNELS define the bundle channels used in the bundle. -# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") -# To re-generate a bundle for other specific channels without changing the standard setup, you can: -# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) -# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") -ifneq ($(origin CHANNELS), undefined) -BUNDLE_CHANNELS := --channels=$(CHANNELS) -endif - -# DEFAULT_CHANNEL defines the default channel used in the bundle. -# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") -# To re-generate a bundle for any other default channel without changing the default setup, you can: -# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) -# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") -ifneq ($(origin DEFAULT_CHANNEL), undefined) -BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) -endif -BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) - -# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. -# This variable is used to construct full image tags for bundle and catalog images. -# -# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both -# nvidia.com/kube-trailblazer-bundle:$VERSION and nvidia.com/kube-trailblazer-catalog:$VERSION. -IMAGE_TAG_BASE ?= nvidia.com/kube-trailblazer - -# BUNDLE_IMG defines the image:tag used for the bundle. -# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) -BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) - -# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command -BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) - -# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests -# You can enable this value if you would like to use SHA Based Digests -# To enable set flag to true -USE_IMAGE_DIGESTS ?= false -ifeq ($(USE_IMAGE_DIGESTS), true) - BUNDLE_GEN_FLAGS += --use-image-digests -endif - -# Set the Operator SDK version to use. By default, what is installed on the system is used. -# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. -OPERATOR_SDK_VERSION ?= v1.32.0 - -# Image URL to use all building/pushing image targets -IMG ?= controller:latest -# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.26.0 - -# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) -ifeq (,$(shell go env GOBIN)) -GOBIN=$(shell go env GOPATH)/bin -else -GOBIN=$(shell go env GOBIN) -endif - -# Setting SHELL to bash allows bash commands to be executed by recipes. -# Options are set to exit when a recipe line exits non-zero or a piped command fails. -SHELL = /usr/bin/env bash -o pipefail -.SHELLFLAGS = -ec - -.PHONY: all -all: build - -##@ General - -# The help target prints out all targets with their descriptions organized -# beneath their categories. The categories are represented by '##@' and the -# target descriptions by '##'. The awk commands is responsible for reading the -# entire set of makefiles included in this invocation, looking for lines of the -# file as xyz: ## something, and then pretty-format the target and help. Then, -# if there's a line with ##@ something, that gets pretty-printed as a category. -# More info on the usage of ANSI control characters for terminal formatting: -# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters -# More info on the awk command: -# http://linuxcommand.org/lc3_adv_awk.php - -.PHONY: help -help: ## Display this help. - @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) - -##@ Development - -.PHONY: manifests -manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases - -.PHONY: generate -generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. - $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." - -.PHONY: fmt -fmt: ## Run go fmt against code. - go fmt ./... - -.PHONY: vet -vet: ## Run go vet against code. - go vet ./... - -.PHONY: test -test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out - -##@ Build - -.PHONY: build -build: manifests generate fmt vet patch ## Build manager binary. - go build -o bin/manager main.go - -.PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go - -# If you wish built the manager image targeting other platforms you can use the --platform flag. -# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. -# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -.PHONY: docker-build -docker-build: go-mod manifests generate patch # test ## Build docker image with the manager. - docker build -t ${IMG} . - -.PHONY: docker-push -docker-push: ## Push docker image with the manager. - docker push ${IMG} - -# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple -# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: -# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ -# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> then the export will fail) -# To properly provided solutions that supports more than one platform you should use this option. -PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le -.PHONY: docker-buildx -docker-buildx: test ## Build and push docker image for the manager for cross-platform support - # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile - sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - docker buildx create --name project-v3-builder - docker buildx use project-v3-builder - - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . - - docker buildx rm project-v3-builder - rm Dockerfile.cross - -##@ Deployment - -ifndef ignore-not-found - ignore-not-found = false -endif - -.PHONY: install -install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | kubectl apply -f - - -.PHONY: uninstall -uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - - -.PHONY: deploy -deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default | kubectl apply -f - - -.PHONY: undeploy -undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - - -##@ Build Dependencies - -## Location to install dependencies to -LOCALBIN ?= $(shell pwd)/bin -$(LOCALBIN): - mkdir -p $(LOCALBIN) - -## Tool Binaries -KUSTOMIZE ?= $(LOCALBIN)/kustomize -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen -ENVTEST ?= $(LOCALBIN)/setup-envtest - -## Tool Versions -KUSTOMIZE_VERSION ?= v3.8.7 -CONTROLLER_TOOLS_VERSION ?= v0.11.1 - -KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" -.PHONY: kustomize -kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading. -$(KUSTOMIZE): $(LOCALBIN) - @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \ - echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ - rm -rf $(LOCALBIN)/kustomize; \ - fi - test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } - -.PHONY: controller-gen -controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten. -$(CONTROLLER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \ - GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) - -.PHONY: envtest -envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. -$(ENVTEST): $(LOCALBIN) - test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest - -.PHONY: operator-sdk -OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk -operator-sdk: ## Download operator-sdk locally if necessary. -ifeq (,$(wildcard $(OPERATOR_SDK))) -ifeq (, $(shell which operator-sdk 2>/dev/null)) - @{ \ - set -e ;\ - mkdir -p $(dir $(OPERATOR_SDK)) ;\ - OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ - curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\ - chmod +x $(OPERATOR_SDK) ;\ - } -else -OPERATOR_SDK = $(shell which operator-sdk) -endif -endif - -.PHONY: bundle -bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. - $(OPERATOR_SDK) generate kustomize manifests -q - cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) - $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) - $(OPERATOR_SDK) bundle validate ./bundle - -.PHONY: bundle-build -bundle-build: ## Build the bundle image. - docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . - -.PHONY: bundle-push -bundle-push: ## Push the bundle image. - $(MAKE) docker-push IMG=$(BUNDLE_IMG) - -.PHONY: opm -OPM = ./bin/opm -opm: ## Download opm locally if necessary. -ifeq (,$(wildcard $(OPM))) -ifeq (,$(shell which opm 2>/dev/null)) - @{ \ - set -e ;\ - mkdir -p $(dir $(OPM)) ;\ - OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ - curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\ - chmod +x $(OPM) ;\ - } -else -OPM = $(shell which opm) -endif -endif - -# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). -# These images MUST exist in a registry and be pull-able. -BUNDLE_IMGS ?= $(BUNDLE_IMG) - -# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). -CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) - -# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. -ifneq ($(origin CATALOG_BASE_IMG), undefined) -FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) -endif - -# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. -# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: -# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator -.PHONY: catalog-build -catalog-build: opm ## Build a catalog image. - $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) - -# Push the catalog image. -.PHONY: catalog-push -catalog-push: ## Push a catalog image. - $(MAKE) docker-push IMG=$(CATALOG_IMG) diff --git a/deploy/k8s-operator/kube-trailblazer/Makefile.helm.mk b/deploy/k8s-operator/kube-trailblazer/Makefile.helm.mk deleted file mode 100644 index 80f3978dd..000000000 --- a/deploy/k8s-operator/kube-trailblazer/Makefile.helm.mk +++ /dev/null @@ -1,62 +0,0 @@ -HELM_CHARTS_DIR = helm-charts -HELM_BUILD_ROOT_DIR = build -HELM_BUILD_DIR = $(HELM_BUILD_ROOT_DIR)/$(HELM_CHARTS_DIR) -HELM_REPOS = $(shell ls -d $(HELM_BUILD_DIR)/*/) - - - -helm-lint: helm helm-copy-charts - @echo "=> HelmRepo: $(HELM_REPOS)" - @for repo in $(HELM_REPOS); do \ - cd $$repo; \ - helm lint -f ../global-values.yaml `ls -d */`; \ - cd ../../..; \ - done - -helm-repo-index: helm-lint - @for repo in $(HELM_REPOS); do \ - cd $$repo; \ - helm package `ls -d */`; \ - file_url=`echo $$repo |sed 's/$(HELM_BUILD_ROOT_DIR)\///g'`; \ - helm repo index . --url=file:///$$file_url; \ - cd ../../..; \ - done - - -helm-copy-charts: - rm -rf $(HELM_BUILD_DIR) - mkdir -p $(HELM_BUILD_DIR) - cp -r $(HELM_CHARTS_DIR)/* $(HELM_BUILD_DIR) - - -helm: -ifeq (, $(shell which helm)) - @{ \ - set -e ;\ - HELM_GEN_TMP_DIR=$$(mktemp -d) ;\ - cd $$HELM_GEN_TMP_DIR ;\ - OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH); \ - curl https://get.helm.sh/helm-v3.6.0-$$OS-$$ARCH.tar.gz -o helm.tar.gz ;\ - tar xvfpz helm.tar.gz ;\ - mv linux-amd64/helm /usr/local/bin ;\ - chmod +x /usr/local/bin/helm ;\ - rm -rf $$HELM_GEN_TMP_DIR ;\ - } -HELM=/usr/local/bin/helm -else -HELM=$(shell which helm) -endif - - -# Operator specific - -CSPLIT ?= csplit - --prefix="" --suppress-matched --suffix-format="%04d_operator_manifests.yaml" /---/ '{*}' 1>/dev/null -HELM_CHART_NAME = developer-llm-operator - -.PHONY: helm-chart - -helm-chart: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - cd $(HELM_CHARTS_DIR)/staging/$(HELM_CHART_NAME)/templates && $(KUSTOMIZE) build ../../../../config/default | $(CSPLIT) -## Remove namespace creation, helm can do that ... - rm $(HELM_CHARTS_DIR)/staging/$(HELM_CHART_NAME)/templates/0000_operator_manifests.yaml diff --git a/deploy/k8s-operator/kube-trailblazer/Makefile.helmer.mk b/deploy/k8s-operator/kube-trailblazer/Makefile.helmer.mk deleted file mode 100644 index 36612e043..000000000 --- a/deploy/k8s-operator/kube-trailblazer/Makefile.helmer.mk +++ /dev/null @@ -1,11 +0,0 @@ - - -.PHONY: go-mod -go-mod: ## Runs go mod tidy/vendor to sync vendor directory with go.mod. - go mod tidy - go mod vendor - -.PHONY: patch -patch: - cp .patches/root.go vendor/helm.sh/helm/v3/pkg/chart/. - diff --git a/deploy/k8s-operator/kube-trailblazer/NVIDIA_AI_Product_License_1Sept2023.pdf b/deploy/k8s-operator/kube-trailblazer/NVIDIA_AI_Product_License_1Sept2023.pdf deleted file mode 100644 index 749f02857..000000000 Binary files a/deploy/k8s-operator/kube-trailblazer/NVIDIA_AI_Product_License_1Sept2023.pdf and /dev/null differ diff --git a/deploy/k8s-operator/kube-trailblazer/PROJECT b/deploy/k8s-operator/kube-trailblazer/PROJECT deleted file mode 100644 index a0762acbf..000000000 --- a/deploy/k8s-operator/kube-trailblazer/PROJECT +++ /dev/null @@ -1,23 +0,0 @@ -# Code generated by tool. DO NOT EDIT. -# This file is used to track the info used to scaffold your project -# and allow the plugins properly work. -# More info: https://book.kubebuilder.io/reference/project-config.html -domain: nvidia.com -layout: -- go.kubebuilder.io/v3 -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} -projectName: kube-trailblazer -repo: github.com/nvidia/kube-trailblazer -resources: -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: nvidia.com - group: package - kind: HelmPipeline - path: github.com/nvidia/kube-trailblazer/api/v1alpha1 - version: v1alpha1 -version: "3" diff --git a/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/groupversion_info.go b/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/groupversion_info.go deleted file mode 100644 index 84c28e79c..000000000 --- a/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package v1alpha1 contains API Schema definitions for the package v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=package.nvidia.com -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "package.nvidia.com", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/helmpipeline_types.go b/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/helmpipeline_types.go deleted file mode 100644 index a04c6e032..000000000 --- a/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/helmpipeline_types.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "github.com/nvidia/kube-trailblazer/pkg/helmer" - operatorv1 "github.com/openshift/api/operator/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// HelmPipelineSpec defines the desired state of HelmPipeline -type HelmPipelineSpec struct { - // Orchard: A planned and managed group of Helm trees. - Pipeline helmer.Pipeline `json:"pipeline"` - // +kubebuilder:validation:Optional - ManagementState operatorv1.ManagementState `json:"managementState,omitempty"` // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster -} - -// HelmPipelineStatus defines the observed state of HelmPipeline -type HelmPipelineStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// HelmPipeline is the Schema for the helmpipelines API -type HelmPipeline struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec HelmPipelineSpec `json:"spec,omitempty"` - Status HelmPipelineStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// HelmPipelineList contains a list of HelmPipeline -type HelmPipelineList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []HelmPipeline `json:"items"` -} - -func init() { - SchemeBuilder.Register(&HelmPipeline{}, &HelmPipelineList{}) -} diff --git a/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/zz_generated.deepcopy.go b/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index a21890900..000000000 --- a/deploy/k8s-operator/kube-trailblazer/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,123 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "github.com/nvidia/kube-trailblazer/pkg/helmer" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HelmPipeline) DeepCopyInto(out *HelmPipeline) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmPipeline. -func (in *HelmPipeline) DeepCopy() *HelmPipeline { - if in == nil { - return nil - } - out := new(HelmPipeline) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *HelmPipeline) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HelmPipelineList) DeepCopyInto(out *HelmPipelineList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]HelmPipeline, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmPipelineList. -func (in *HelmPipelineList) DeepCopy() *HelmPipelineList { - if in == nil { - return nil - } - out := new(HelmPipelineList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *HelmPipelineList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HelmPipelineSpec) DeepCopyInto(out *HelmPipelineSpec) { - *out = *in - if in.Pipeline != nil { - in, out := &in.Pipeline, &out.Pipeline - *out = make(helmer.Pipeline, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmPipelineSpec. -func (in *HelmPipelineSpec) DeepCopy() *HelmPipelineSpec { - if in == nil { - return nil - } - out := new(HelmPipelineSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HelmPipelineStatus) DeepCopyInto(out *HelmPipelineStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmPipelineStatus. -func (in *HelmPipelineStatus) DeepCopy() *HelmPipelineStatus { - if in == nil { - return nil - } - out := new(HelmPipelineStatus) - in.DeepCopyInto(out) - return out -} diff --git a/deploy/k8s-operator/kube-trailblazer/config/crd/bases/package.nvidia.com_helmpipelines.yaml b/deploy/k8s-operator/kube-trailblazer/config/crd/bases/package.nvidia.com_helmpipelines.yaml deleted file mode 100644 index a3c682b48..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/crd/bases/package.nvidia.com_helmpipelines.yaml +++ /dev/null @@ -1,234 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null - name: helmpipelines.package.nvidia.com -spec: - group: package.nvidia.com - names: - kind: HelmPipeline - listKind: HelmPipelineList - plural: helmpipelines - singular: helmpipeline - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: HelmPipeline is the Schema for the helmpipelines API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: HelmPipelineSpec defines the desired state of HelmPipeline - properties: - managementState: - pattern: ^(Managed|Unmanaged|Force|Removed)$ - type: string - pipeline: - description: 'Orchard: A planned and managed group of Helm trees.' - items: - description: A shelter of vines or branches or of latticework covered - with climbing shrubs or vines, also latin for tree - properties: - chartSpec: - properties: - atomic: - description: Atomic indicates whether to install resources - atomically. 'Wait' will automatically be set to true when - using Atomic. - type: boolean - chart: - type: string - cleanupOnFail: - description: CleanupOnFail indicates whether to cleanup - the release on failure. - type: boolean - createNamespace: - description: CreateNamespace indicates whether to create - the namespace if it does not exist. - type: boolean - dependencyUpdate: - description: DependencyUpdate indicates whether to update - the chart release if the dependencies have changed. - type: boolean - description: - description: Description specifies a custom description - for the uninstalled release - type: string - disableHooks: - description: DisableHooks indicates whether to disable hooks. - type: boolean - dryRun: - description: DryRun indicates whether to perform a dry run. - type: boolean - force: - description: Force indicates whether to force the operation. - type: boolean - generateName: - description: GenerateName indicates that the release name - should be generated. - type: boolean - keepHistory: - description: KeepHistory indicates whether to retain or - purge the release history during uninstall - type: boolean - maxHistory: - description: MaxHistory limits the maximum number of revisions - saved per release. - type: integer - nameTemplate: - description: NameTemplate is the template used to generate - the release name if GenerateName is configured. - type: string - namespace: - description: Namespace where the chart release is deployed. - Note that helmclient.Options.Namespace should ideally - match the namespace configured here. - type: string - recreate: - description: Recreate indicates whether to recreate the - release if it already exists. - type: boolean - release: - type: string - replace: - description: Replace indicates whether to replace the chart - release if it already exists. - type: boolean - resetValues: - description: ResetValues indicates whether to reset the - values.yaml file during installation. - type: boolean - reuseValues: - description: ReuseValues indicates whether to reuse the - values.yaml file during installation. - type: boolean - skipCRDs: - description: SkipCRDs indicates whether to skip CRDs during - installation. - type: boolean - subNotes: - description: SubNotes indicates whether to print sub-notes. - type: boolean - timeout: - description: Timeout configures the time to wait for any - individual Kubernetes operation (like Jobs for hooks). - format: int64 - type: integer - upgradeCRDs: - description: Upgrade indicates whether to perform a CRD - upgrade during installation. - type: boolean - valuesOptions: - description: Specify values similar to the cli - properties: - JSONValues: - items: - type: string - type: array - fileValues: - items: - type: string - type: array - strinValues: - items: - type: string - type: array - valueFiles: - items: - type: string - type: array - values: - items: - type: string - type: array - required: - - JSONValues - - fileValues - - strinValues - - valueFiles - - values - type: object - valuesYaml: - description: ValuesYaml is the values.yaml content. use - string instead of map[string]interface{} https://github.com/kubernetes-sigs/kubebuilder/issues/528#issuecomment-466449483 - and https://github.com/kubernetes-sigs/controller-tools/pull/317 - type: string - version: - description: Version of the chart release. - type: string - wait: - description: Wait indicates whether to wait for the release - to be deployed or not. - type: boolean - waitForJobs: - description: WaitForJobs indicates whether to wait for completion - of release Jobs before marking the release as successful. - 'Wait' has to be specified for this to take effect. The - timeout may be specified via the 'Timeout' field. - type: boolean - required: - - chart - type: object - chartValues: - description: TODO ChartValues json.RawMessage `json:"chartValues"` - type: object - x-kubernetes-preserve-unknown-fields: true - releaseName: - type: string - repoEntry: - description: Entry represents a collection of parameters for - chart repository, since we cannot annotate the internal helm - struct we're doing it here - properties: - caFile: - type: string - certFile: - type: string - insecure_skip_tls_verify: - type: boolean - keyFile: - type: string - name: - type: string - pass_credentials_all: - type: boolean - password: - type: string - url: - type: string - username: - type: string - required: - - url - type: object - required: - - chartSpec - - repoEntry - type: object - type: array - required: - - pipeline - type: object - status: - description: HelmPipelineStatus defines the observed state of HelmPipeline - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/deploy/k8s-operator/kube-trailblazer/config/crd/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/crd/kustomization.yaml deleted file mode 100644 index f6c2911b7..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/crd/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# This kustomization.yaml is not intended to be run by itself, -# since it depends on service name and namespace that are out of this kustomize package. -# It should be run by config/default -resources: -- bases/package.nvidia.com_helmpipelines.yaml -#+kubebuilder:scaffold:crdkustomizeresource - -patchesStrategicMerge: -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. -# patches here are for enabling the conversion webhook for each CRD -#- patches/webhook_in_helmpipelines.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_helmpipelines.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch - -# the following config is for teaching kustomize how to do kustomization for CRDs. -configurations: -- kustomizeconfig.yaml diff --git a/deploy/k8s-operator/kube-trailblazer/config/crd/kustomizeconfig.yaml b/deploy/k8s-operator/kube-trailblazer/config/crd/kustomizeconfig.yaml deleted file mode 100644 index ec5c150a9..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/crd/kustomizeconfig.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# This file is for teaching kustomize how to substitute name and namespace reference in CRD -nameReference: -- kind: Service - version: v1 - fieldSpecs: - - kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/name - -namespace: -- kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/namespace - create: false - -varReference: -- path: metadata/annotations diff --git a/deploy/k8s-operator/kube-trailblazer/config/crd/patches/cainjection_in_helmpipelines.yaml b/deploy/k8s-operator/kube-trailblazer/config/crd/patches/cainjection_in_helmpipelines.yaml deleted file mode 100644 index 4ca9b78ba..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/crd/patches/cainjection_in_helmpipelines.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: helmpipelines.package.nvidia.com diff --git a/deploy/k8s-operator/kube-trailblazer/config/crd/patches/webhook_in_helmpipelines.yaml b/deploy/k8s-operator/kube-trailblazer/config/crd/patches/webhook_in_helmpipelines.yaml deleted file mode 100644 index e52065b94..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/crd/patches/webhook_in_helmpipelines.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: helmpipelines.package.nvidia.com -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/deploy/k8s-operator/kube-trailblazer/config/default/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/default/kustomization.yaml deleted file mode 100644 index be30e9553..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/default/kustomization.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# Adds namespace to all resources. -namespace: kube-trailblazer-system - -# Value of this field is prepended to the -# names of all resources, e.g. a deployment named -# "wordpress" becomes "alices-wordpress". -# Note that it should also match with the prefix (text before '-') of the namespace -# field above. -namePrefix: kube-trailblazer- - -# Labels to add to all resources and selectors. -#commonLabels: -# someName: someValue - -bases: -- ../crd -- ../rbac -- ../manager -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in -# crd/kustomization.yaml -#- ../webhook -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. -#- ../certmanager -# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. -#- ../prometheus - -patchesStrategicMerge: -# Protect the /metrics endpoint by putting it behind auth. -# If you want your controller-manager to expose the /metrics -# endpoint w/o any authn/z, please comment the following line. -- manager_auth_proxy_patch.yaml - - - -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in -# crd/kustomization.yaml -#- manager_webhook_patch.yaml - -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. -# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. -# 'CERTMANAGER' needs to be enabled to use ca injection -#- webhookcainjection_patch.yaml - -# the following config is for teaching kustomize how to do var substitution -vars: -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. -#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR -# objref: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -# fieldref: -# fieldpath: metadata.namespace -#- name: CERTIFICATE_NAME -# objref: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -#- name: SERVICE_NAMESPACE # namespace of the service -# objref: -# kind: Service -# version: v1 -# name: webhook-service -# fieldref: -# fieldpath: metadata.namespace -#- name: SERVICE_NAME -# objref: -# kind: Service -# version: v1 -# name: webhook-service diff --git a/deploy/k8s-operator/kube-trailblazer/config/default/manager_auth_proxy_patch.yaml b/deploy/k8s-operator/kube-trailblazer/config/default/manager_auth_proxy_patch.yaml deleted file mode 100644 index b75126616..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/default/manager_auth_proxy_patch.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# This patch inject a sidecar container which is a HTTP proxy for the -# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - arm64 - - ppc64le - - s390x - - key: kubernetes.io/os - operator: In - values: - - linux - containers: - - name: kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" - - "--logtostderr=true" - - "--v=0" - ports: - - containerPort: 8443 - protocol: TCP - name: https - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 5m - memory: 64Mi - - name: manager - args: - - "--health-probe-bind-address=:8081" - - "--metrics-bind-address=127.0.0.1:8080" - - "--leader-elect" diff --git a/deploy/k8s-operator/kube-trailblazer/config/default/manager_config_patch.yaml b/deploy/k8s-operator/kube-trailblazer/config/default/manager_config_patch.yaml deleted file mode 100644 index f6f589169..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/default/manager_config_patch.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: manager diff --git a/deploy/k8s-operator/kube-trailblazer/config/manager/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/manager/kustomization.yaml deleted file mode 100644 index b20824356..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/manager/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -resources: -- manager.yaml -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -images: -- name: controller - newName: nvcr.io/nvstaging/cloud-native/developer-llm-operator - newTag: v0.0.1 diff --git a/deploy/k8s-operator/kube-trailblazer/config/manager/manager.yaml b/deploy/k8s-operator/kube-trailblazer/config/manager/manager.yaml deleted file mode 100644 index ec2f77cb3..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/manager/manager.yaml +++ /dev/null @@ -1,105 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: namespace - app.kubernetes.io/instance: system - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system - labels: - control-plane: controller-manager - app.kubernetes.io/name: deployment - app.kubernetes.io/instance: controller-manager - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize -spec: - selector: - matchLabels: - control-plane: controller-manager - replicas: 1 - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - labels: - control-plane: controller-manager - spec: - # TODO(user): Uncomment the following code to configure the nodeAffinity expression - # according to the platforms which are supported by your solution. - # It is considered best practice to support multiple architectures. You can - # build your manager image using the makefile target docker-buildx. - # affinity: - # nodeAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # nodeSelectorTerms: - # - matchExpressions: - # - key: kubernetes.io/arch - # operator: In - # values: - # - amd64 - # - arm64 - # - ppc64le - # - s390x - # - key: kubernetes.io/os - # operator: In - # values: - # - linux - securityContext: - runAsNonRoot: true - # TODO(user): For common cases that do not require escalating privileges - # it is recommended to ensure that all your Pods/Containers are restrictive. - # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted - # Please uncomment the following code if your project does NOT have to work on old Kubernetes - # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). - # seccompProfile: - # type: RuntimeDefault - containers: - - command: - - /manager - args: - - --leader-elect - image: controller:latest - name: manager - imagePullPolicy: Always - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - # TODO(user): Configure the resources accordingly based on the project requirements. - # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 100m - memory: 128Mi - serviceAccountName: controller-manager - terminationGracePeriodSeconds: 10 - imagePullSecrets: - - name: nvcrio diff --git a/deploy/k8s-operator/kube-trailblazer/config/manifests/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/manifests/kustomization.yaml deleted file mode 100644 index 4230a0127..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/manifests/kustomization.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# These resources constitute the fully configured set of manifests -# used to generate the 'manifests/' directory in a bundle. -resources: -- bases/kube-trailblazer.clusterserviceversion.yaml -- ../default -- ../samples -- ../scorecard - -# [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. -# Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. -# These patches remove the unnecessary "cert" volume and its manager container volumeMount. -#patchesJson6902: -#- target: -# group: apps -# version: v1 -# kind: Deployment -# name: controller-manager -# namespace: system -# patch: |- -# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. -# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. -# - op: remove -# path: /spec/template/spec/containers/1/volumeMounts/0 -# # Remove the "cert" volume, since OLM will create and mount a set of certs. -# # Update the indices in this path if adding or removing volumes in the manager's Deployment. -# - op: remove -# path: /spec/template/spec/volumes/0 diff --git a/deploy/k8s-operator/kube-trailblazer/config/prometheus/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/prometheus/kustomization.yaml deleted file mode 100644 index ed137168a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/prometheus/kustomization.yaml +++ /dev/null @@ -1,2 +0,0 @@ -resources: -- monitor.yaml diff --git a/deploy/k8s-operator/kube-trailblazer/config/prometheus/monitor.yaml b/deploy/k8s-operator/kube-trailblazer/config/prometheus/monitor.yaml deleted file mode 100644 index aa105981c..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/prometheus/monitor.yaml +++ /dev/null @@ -1,26 +0,0 @@ - -# Prometheus Monitor Service (Metrics) -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: servicemonitor - app.kubernetes.io/instance: controller-manager-metrics-monitor - app.kubernetes.io/component: metrics - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: controller-manager-metrics-monitor - namespace: system -spec: - endpoints: - - path: /metrics - port: https - scheme: https - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token - tlsConfig: - insecureSkipVerify: true - selector: - matchLabels: - control-plane: controller-manager diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_client_clusterrole.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_client_clusterrole.yaml deleted file mode 100644 index 9dcad6a9f..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_client_clusterrole.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: metrics-reader - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: metrics-reader -rules: -- nonResourceURLs: - - "/metrics" - verbs: - - get diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_role.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_role.yaml deleted file mode 100644 index c893b21ab..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: proxy-role - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: proxy-role -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_role_binding.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_role_binding.yaml deleted file mode 100644 index 22adf7212..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_role_binding.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/instance: proxy-rolebinding - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: proxy-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_service.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_service.yaml deleted file mode 100644 index 1f6f8afc3..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/auth_proxy_service.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: service - app.kubernetes.io/instance: controller-manager-metrics-service - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: controller-manager-metrics-service - namespace: system -spec: - ports: - - name: https - port: 8443 - protocol: TCP - targetPort: https - selector: - control-plane: controller-manager diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/helmpipeline_editor_role.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/helmpipeline_editor_role.yaml deleted file mode 100644 index 85316651e..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/helmpipeline_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit helmpipelines. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: helmpipeline-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: helmpipeline-editor-role -rules: -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines/status - verbs: - - get diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/helmpipeline_viewer_role.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/helmpipeline_viewer_role.yaml deleted file mode 100644 index 2f837d67a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/helmpipeline_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view helmpipelines. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: helmpipeline-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: helmpipeline-viewer-role -rules: -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines - verbs: - - get - - list - - watch -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines/status - verbs: - - get diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/kustomization.yaml deleted file mode 100644 index 731832a6a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/kustomization.yaml +++ /dev/null @@ -1,18 +0,0 @@ -resources: -# All RBAC will be applied under this service account in -# the deployment namespace. You may comment out this resource -# if your manager will use a service account that exists at -# runtime. Be sure to update RoleBinding and ClusterRoleBinding -# subjects if changing service account names. -- service_account.yaml -- role.yaml -- role_binding.yaml -- leader_election_role.yaml -- leader_election_role_binding.yaml -# Comment the following 4 lines if you want to disable -# the auth proxy (https://github.com/brancz/kube-rbac-proxy) -# which protects your /metrics endpoint. -- auth_proxy_service.yaml -- auth_proxy_role.yaml -- auth_proxy_role_binding.yaml -- auth_proxy_client_clusterrole.yaml diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/leader_election_role.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/leader_election_role.yaml deleted file mode 100644 index f7fc4f769..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/leader_election_role.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# permissions to do leader election. -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - labels: - app.kubernetes.io/name: role - app.kubernetes.io/instance: leader-election-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: leader-election-role -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/leader_election_role_binding.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/leader_election_role_binding.yaml deleted file mode 100644 index 881e07c93..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/leader_election_role_binding.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/name: rolebinding - app.kubernetes.io/instance: leader-election-rolebinding - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: leader-election-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: leader-election-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/role.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/role.yaml deleted file mode 100644 index 4e80601cf..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/role.yaml +++ /dev/null @@ -1,1228 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: manager-role -rules: -- apiGroups: - - "" - resources: - - nodes/finalizers - verbs: - - update -- apiGroups: - - "" - resources: - - nodes/proxy - verbs: - - get -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - get - - list - - patch - - update -- apiGroups: - - "" - resources: - - pods - verbs: - - deletecollection -- apiGroups: - - "" - resources: - - podtemplates - verbs: - - create - - get - - list - - update - - watch -- apiGroups: - - "" - resources: - - podtemplates/finalizers - verbs: - - update -- apiGroups: - - '*' - resources: - - cronjobs - verbs: - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - '*' - resources: - - daemonsets - verbs: - - get -- apiGroups: - - '*' - resources: - - deployments - verbs: - - get -- apiGroups: - - '*' - resources: - - imagepolicies - verbs: - - delete - - get - - update -- apiGroups: - - '*' - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - '*' - resources: - - mutatingwebhookconfigurations - verbs: - - get -- apiGroups: - - '*' - resources: - - pods - verbs: - - get -- apiGroups: - - '*' - resources: - - replicacontrollers - verbs: - - get -- apiGroups: - - '*' - resources: - - replicasets - verbs: - - get -- apiGroups: - - '*' - resources: - - statefulsets - verbs: - - get -- apiGroups: - - acme.cert-manager.io - resources: - - challenges - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - acme.cert-manager.io - resources: - - challenges/finalizers - verbs: - - update -- apiGroups: - - acme.cert-manager.io - resources: - - challenges/status - verbs: - - update -- apiGroups: - - acme.cert-manager.io - resources: - - orders - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - acme.cert-manager.io - resources: - - orders/finalizers - verbs: - - update -- apiGroups: - - acme.cert-manager.io - resources: - - orders/status - verbs: - - update -- apiGroups: - - admissionregistration.k8s.io - resources: - - mutatingwebhookconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - admissionregistration.k8s.io - resources: - - validatingwebhookconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - admissionregistration.k8s.io/v1beta1 - resources: - - mutatingwebhookconfigurations - verbs: - - create - - delete - - list - - update -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apiregistration.k8s.io - resources: - - apiservices - verbs: - - get - - list - - update - - watch -- apiGroups: - - apps - resources: - - daemonsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resourceNames: - - shipwright-build - resources: - - deployments/finalizers - verbs: - - update -- apiGroups: - - apps - resources: - - replicasets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - auditregistration.k8s.io - resources: - - auditsinks - verbs: - - get - - list - - update - - watch -- apiGroups: - - batch - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - batch - resources: - - jobs/finalizers - verbs: - - update -- apiGroups: - - build.openshift.io - resources: - - buildconfigs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - build.openshift.io - resources: - - builds - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - certificaterequests - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - certificaterequests/finalizers - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - certificaterequests/status - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - certificates - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - certificates/finalizers - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - certificates/status - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - clusterissuers - verbs: - - deletecollection - - get - - list - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - clusterissuers/status - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - issuers - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - issuers/status - verbs: - - update -- apiGroups: - - cert-manager.io - resourceNames: - - clusterissuers.cert-manager.io/* - resources: - - signers - verbs: - - approve -- apiGroups: - - cert-manager.io - resourceNames: - - issuers.cert-manager.io/* - resources: - - signers - verbs: - - approve -- apiGroups: - - certificates.k8s.io - resources: - - certificatesigningrequests - verbs: - - get - - list - - update - - watch -- apiGroups: - - certificates.k8s.io - resources: - - certificatesigningrequests/status - verbs: - - update -- apiGroups: - - certificates.k8s.io - resourceNames: - - clusterissuers.cert-manager.io/* - resources: - - signers - verbs: - - sign -- apiGroups: - - certificates.k8s.io - resourceNames: - - issuers.cert-manager.io/* - resources: - - signers - verbs: - - sign -- apiGroups: - - config.openshift.io - resources: - - clusterversions - verbs: - - get -- apiGroups: - - config.openshift.io - resources: - - proxies - verbs: - - get - - list -- apiGroups: - - connaisseur.policy - resources: - - imagepolicies - verbs: - - create -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-cainjector-election-core - resources: - - leases - verbs: - - patch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-cainjector-leader-election - resources: - - leases - verbs: - - patch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-cainjector-leader-election-core - resources: - - leases - verbs: - - patch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-controller - resources: - - leases - verbs: - - patch -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - imagestreams/layers - verbs: - - get -- apiGroups: - - "" - resources: - - namespaces - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims/status - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - pods - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - pods/log - verbs: - - get -- apiGroups: - - "" - resources: - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - services/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - csi.storage.k8s.io - resources: - - csidrivers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - extensions - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - fpga.silicom.dk - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - image.openshift.io - resources: - - imagestreams - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - image.openshift.io - resources: - - imagestreams/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - image.openshift.io - resources: - - imagestreams/layers - verbs: - - get -- apiGroups: - - infoscale.veritas.com - resources: - - infoscaleclusters - verbs: - - get - - list - - patch - - update -- apiGroups: - - monitoring.coreos.com - resources: - - prometheusrules - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - networking.k8s.io - resources: - - clustercidrs - verbs: - - list - - watch -- apiGroups: - - networking.k8s.io - resources: - - ingresses - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - networking.k8s.io - resources: - - ingresses/finalizers - verbs: - - update -- apiGroups: - - networking.x-k8s.io - resources: - - gateways - verbs: - - get - - list - - watch -- apiGroups: - - networking.x-k8s.io - resources: - - gateways/finalizers - verbs: - - update -- apiGroups: - - networking.x-k8s.io - resources: - - httproutes - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - networking.x-k8s.io - resources: - - httproutes/finalisers - verbs: - - update -- apiGroups: - - nfd.k8s-sigs.io - resources: - - nodefeaturerules - verbs: - - get - - list - - watch -- apiGroups: - - nfd.k8s-sigs.io - resources: - - nodefeatures - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - nvidia.com - resources: - - clusterpolicies - verbs: - - get - - list - - patch - - watch -- apiGroups: - - operator.cert-manager.io - resources: - - certmanagers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - operators.coreos.com - resources: - - operatorgroups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - operators.coreos.com - resources: - - subscriptions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines/finalizers - verbs: - - update -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines/status - verbs: - - get - - patch - - update -- apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterrolebindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterroles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - route.openshift.io - resources: - - routes/custom-host - verbs: - - create -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - create - - delete - - get - - list - - patch - - update - - use - - watch -- apiGroups: - - shipwright.io - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - shipwright.io - resources: - - buildruns - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - shipwright.io - resources: - - buildstrategies - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - shipwright.io - resources: - - clusterbuildstrategies - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotclasses - verbs: - - get - - list - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents/status - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshots - verbs: - - get - - list - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshots/status - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - sro.openshift.io - resources: - - specialresources - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - sro.openshift.io - resources: - - specialresources/finalizers - verbs: - - get - - patch - - update -- apiGroups: - - sro.openshift.io - resources: - - specialresources/status - verbs: - - get - - patch - - update -- apiGroups: - - storage.k8s.io - resources: - - csidrivers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - storage.k8s.io - resources: - - csinodes - verbs: - - get - - list - - watch -- apiGroups: - - storage.k8s.io - resources: - - storageclasses - verbs: - - get - - list - - watch -- apiGroups: - - storage.k8s.io - resources: - - volumeattachments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - sts.silicom.com - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - tekton.dev - resources: - - taskruns - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - tekton.dev - resources: - - tasks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - topology.node.k8s.io - resources: - - noderesourcetopologies - verbs: - - delete - - list diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/role_binding.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/role_binding.yaml deleted file mode 100644 index 64c93eef5..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/role_binding.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/instance: manager-rolebinding - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: manager-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/deploy/k8s-operator/kube-trailblazer/config/rbac/service_account.yaml b/deploy/k8s-operator/kube-trailblazer/config/rbac/service_account.yaml deleted file mode 100644 index b92e8b958..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/rbac/service_account.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/name: serviceaccount - app.kubernetes.io/instance: controller-manager - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - name: controller-manager - namespace: system diff --git a/deploy/k8s-operator/kube-trailblazer/config/samples/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/samples/kustomization.yaml deleted file mode 100644 index 828521d79..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/samples/kustomization.yaml +++ /dev/null @@ -1,4 +0,0 @@ -## Append samples you want in your CSV to this file as resources ## -resources: -- package_v1alpha1_helmpipeline.yaml -#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/deploy/k8s-operator/kube-trailblazer/config/samples/package_v1alpha1_helmpipeline.yaml b/deploy/k8s-operator/kube-trailblazer/config/samples/package_v1alpha1_helmpipeline.yaml deleted file mode 100644 index bdf4d4c20..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/samples/package_v1alpha1_helmpipeline.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: package.nvidia.com/v1alpha1 -kind: HelmPipeline -metadata: - labels: - app.kubernetes.io/name: helmpipeline - app.kubernetes.io/instance: helmpipeline-sample - app.kubernetes.io/part-of: kube-trailblazer - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: kube-trailblazer - name: helmpipeline-sample -spec: - # TODO(user): Add fields here diff --git a/deploy/k8s-operator/kube-trailblazer/config/scorecard/bases/config.yaml b/deploy/k8s-operator/kube-trailblazer/config/scorecard/bases/config.yaml deleted file mode 100644 index c77047841..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/scorecard/bases/config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: scorecard.operatorframework.io/v1alpha3 -kind: Configuration -metadata: - name: config -stages: -- parallel: true - tests: [] diff --git a/deploy/k8s-operator/kube-trailblazer/config/scorecard/kustomization.yaml b/deploy/k8s-operator/kube-trailblazer/config/scorecard/kustomization.yaml deleted file mode 100644 index 50cd2d084..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/scorecard/kustomization.yaml +++ /dev/null @@ -1,16 +0,0 @@ -resources: -- bases/config.yaml -patchesJson6902: -- path: patches/basic.config.yaml - target: - group: scorecard.operatorframework.io - version: v1alpha3 - kind: Configuration - name: config -- path: patches/olm.config.yaml - target: - group: scorecard.operatorframework.io - version: v1alpha3 - kind: Configuration - name: config -#+kubebuilder:scaffold:patchesJson6902 diff --git a/deploy/k8s-operator/kube-trailblazer/config/scorecard/patches/basic.config.yaml b/deploy/k8s-operator/kube-trailblazer/config/scorecard/patches/basic.config.yaml deleted file mode 100644 index 472a98823..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/scorecard/patches/basic.config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - basic-check-spec - image: quay.io/operator-framework/scorecard-test:v1.32.0 - labels: - suite: basic - test: basic-check-spec-test diff --git a/deploy/k8s-operator/kube-trailblazer/config/scorecard/patches/olm.config.yaml b/deploy/k8s-operator/kube-trailblazer/config/scorecard/patches/olm.config.yaml deleted file mode 100644 index 343c6d8d8..000000000 --- a/deploy/k8s-operator/kube-trailblazer/config/scorecard/patches/olm.config.yaml +++ /dev/null @@ -1,50 +0,0 @@ -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:v1.32.0 - labels: - suite: olm - test: olm-bundle-validation-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:v1.32.0 - labels: - suite: olm - test: olm-crds-have-validation-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-crds-have-resources - image: quay.io/operator-framework/scorecard-test:v1.32.0 - labels: - suite: olm - test: olm-crds-have-resources-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:v1.32.0 - labels: - suite: olm - test: olm-spec-descriptors-test -- op: add - path: /stages/0/tests/- - value: - entrypoint: - - scorecard-test - - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:v1.32.0 - labels: - suite: olm - test: olm-status-descriptors-test diff --git a/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline.go b/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline.go deleted file mode 100644 index 8f24f5bb5..000000000 --- a/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline.go +++ /dev/null @@ -1,37 +0,0 @@ -package controllers - -import ( - "context" - - "github.com/nvidia/kube-trailblazer/api/v1alpha1" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func findRequestingHelmPipeline(a []v1alpha1.HelmPipeline, x string, by string) (int, bool) { - for i, n := range a { - if by == "Name" { - if x == n.GetName() { - return i, true - } - } - } - return -1, false -} - -func (r *HelmPipelineReconciler) listHelmPipelines(ctx context.Context, req ctrl.Request) (*v1alpha1.HelmPipeline, *v1alpha1.HelmPipelineList, error) { - helmPipelines := &v1alpha1.HelmPipelineList{} - - opts := []client.ListOption{} - err := r.KubeClient.List(ctx, helmPipelines, opts...) - if err != nil { - return nil, nil, err - } - - var idx int - var found bool - if idx, found = findRequestingHelmPipeline(helmPipelines.Items, req.Name, "Name"); !found { - return nil, nil, nil - } - return &helmPipelines.Items[idx], helmPipelines, nil -} diff --git a/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline_controller.go b/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline_controller.go deleted file mode 100644 index 2921041d2..000000000 --- a/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline_controller.go +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllers - -import ( - "context" - "fmt" - - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - storagev1 "k8s.io/api/storage/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - v1alpha1 "github.com/nvidia/kube-trailblazer/api/v1alpha1" - "github.com/nvidia/kube-trailblazer/pkg/clients" - "github.com/nvidia/kube-trailblazer/pkg/filter" - "github.com/nvidia/kube-trailblazer/pkg/helmer" -) - -// HelmPipelineReconciler reconciles a HelmPipeline object -type HelmPipelineReconciler struct { - client.Client - Scheme *runtime.Scheme - Filter filter.Filter - KubeClient clients.ClientsInterface - RestConf *rest.Config -} - -//+kubebuilder:rbac:groups=package.nvidia.com,resources=helmpipelines,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=package.nvidia.com,resources=helmpipelines/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=package.nvidia.com,resources=helmpipelines/finalizers,verbs=update - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the HelmPipeline object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile -func (r *HelmPipelineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) - - klog.Infof("%s -- reconciling -- request %s:%s", r.Filter.GetMode(), req.Namespace, req.Name) - - klog.Info("TODO: preflight checks") - - tb, _, err := r.listHelmPipelines(ctx, req) - if err != nil { - klog.Error(err, "[Reconcile]\tfailed to list HelmOrchards") - return ctrl.Result{}, err - } - - for { - var ok bool - var tb *v1alpha1.HelmPipeline - - item := filter.WorkStack["DELETE"].Pop() - if item == nil { - break - } - if tb, ok = item.(*v1alpha1.HelmPipeline); !ok { - klog.Info(fmt.Sprintf("DEBUG WorkStack Item: %+v", item)) - //panic(errors.New("owned object is not a HelmPipeline")) - continue - - } - err = helmer.ReconcileDelete(tb.Spec.Pipeline, r.RestConf) - if err != nil { - klog.Info("SUCCESS: ReconcileDelete") - return ctrl.Result{}, err - } - } - - // This happens if Helmer was reconciling and the HelmOrchard was deleted - if tb == nil { - klog.Info("SUCCESS: reconcile (tb == nil)") - return ctrl.Result{}, nil - } - - klog.Infof("[Reconcile] -- %s -- HelmPipeline %s:%s", r.Filter.GetMode(), tb.GetNamespace(), tb.GetName()) - releases, err := helmer.ReconcileCreate(tb.Spec.Pipeline, r.RestConf) - if err != nil { - klog.Warning(err, "[Reconcile]\trequeue request due to error") - return ctrl.Result{Requeue: true}, nil - } - - klog.Info("TODO: metrics") - for _, release := range releases { - klog.Infof("[Reconcile]\tRELEASES: %s:%s", release.Namespace, release.Name) - } - - klog.Info("SUCCESS: reconcile") - return ctrl.Result{}, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *HelmPipelineReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.HelmPipeline{}). - Owns(&v1.Pod{}). - Owns(&appsv1.DaemonSet{}). - Owns(&appsv1.Deployment{}). - Owns(&storagev1.CSIDriver{}). - Owns(&v1.ConfigMap{}). - Owns(&v1.ServiceAccount{}). - Owns(&rbacv1.Role{}). - Owns(&rbacv1.RoleBinding{}). - Owns(&rbacv1.ClusterRole{}). - Owns(&rbacv1.ClusterRoleBinding{}). - Owns(&v1.Secret{}). - WithEventFilter(r.Filter.GetPredicates()). - Complete(r) -} diff --git a/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline_rbac.go b/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline_rbac.go deleted file mode 100644 index d0ec76a7e..000000000 --- a/deploy/k8s-operator/kube-trailblazer/controllers/helmpipeline_rbac.go +++ /dev/null @@ -1,12 +0,0 @@ -package controllers - -//+kubebuilder:rbac:groups=package.nvidia.com,resources=helmpipelines,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=package.nvidia.com,resources=helmpipelines/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=package.nvidia.com,resources=helmpipelines/finalizers,verbs=update -//+kubebuilder:rbac:groups="",resources=nodes/status,verbs=get;list -//+kubebuilder:rbac:groups="",resources=nodes/proxy,verbs=get -//+kubebuilder:rbac:groups=nfd.k8s-sigs.io,resources=nodefeaturerules,verbs=get;list;watch -//+kubebuilder:rbac:groups=nfd.k8s-sigs.io,resources=nodefeatures,verbs=get;list;watch;delete;create;update -//+kubebuilder:rbac:groups=topology.node.k8s.io,resources=noderesourcetopologies,verbs=delete;list -//+kubebuilder:rbac:groups=networking.k8s.io, resources=clustercidrs, verbs=list;watch -//+kubebuilder:rbac:groups=nvidia.com, resources=clusterpolicies, verbs=get;list;watch;patch diff --git a/deploy/k8s-operator/kube-trailblazer/controllers/suite_test.go b/deploy/k8s-operator/kube-trailblazer/controllers/suite_test.go deleted file mode 100644 index e8aafe4f0..000000000 --- a/deploy/k8s-operator/kube-trailblazer/controllers/suite_test.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllers - -import ( - "path/filepath" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - packagev1alpha1 "github.com/nvidia/kube-trailblazer/api/v1alpha1" - //+kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Controller Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - err = packagev1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/deploy/k8s-operator/kube-trailblazer/go.mod b/deploy/k8s-operator/kube-trailblazer/go.mod deleted file mode 100644 index b675965e0..000000000 --- a/deploy/k8s-operator/kube-trailblazer/go.mod +++ /dev/null @@ -1,167 +0,0 @@ -module github.com/nvidia/kube-trailblazer - -go 1.20 - -replace github.com/mittwald/go-helm-client => /zvonkok/github.com/zvonkok/go-helm-client - -require ( - github.com/golang/mock v1.6.0 - github.com/mittwald/go-helm-client v0.9.0 - github.com/onsi/ginkgo/v2 v2.11.0 - github.com/onsi/gomega v1.27.10 - github.com/openshift-psap/special-resource-operator v0.0.0-20220818111522-5e97683a2041 - github.com/openshift/api v0.0.0-20231128111040-e1845c5a7acd - github.com/openshift/client-go v0.0.0-20231121143148-910ca30a1a9a - github.com/pkg/errors v0.9.1 - github.com/urfave/cli/v2 v2.26.0 - golang.design/x/lockfree v0.0.1 - helm.sh/helm/v3 v3.13.2 - k8s.io/api v0.28.4 - k8s.io/apimachinery v0.28.4 - k8s.io/cli-runtime v0.28.4 - k8s.io/client-go v0.28.4 - k8s.io/klog/v2 v2.100.1 - sigs.k8s.io/controller-runtime v0.16.3 - sigs.k8s.io/yaml v1.3.0 -) - -require ( - github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/BurntSushi/toml v1.3.2 // indirect - github.com/MakeNowJust/heredoc v1.0.0 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect - github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/Microsoft/hcsshim v0.11.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/changkun/lockfree v0.0.1 // indirect - github.com/containerd/containerd v1.7.6 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.7+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-metrics v0.0.1 // indirect - github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect - github.com/fatih/color v1.13.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-logr/zapr v1.2.4 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/gobwas/glob v0.2.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gosuri/uitable v0.0.4 // indirect - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.0 // indirect - github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect - github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect - github.com/lib/pq v1.10.9 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/locker v1.0.1 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/morikuni/aec v1.0.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect - github.com/rivo/uniseg v0.4.2 // indirect - github.com/rubenv/sql-migrate v1.5.2 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.7.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/xlab/treeprint v1.2.0 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.opentelemetry.io/otel v1.14.0 // indirect - go.opentelemetry.io/otel/trace v1.14.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect - golang.org/x/crypto v0.15.0 // indirect - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.14.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.15.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.3 // indirect - k8s.io/apiserver v0.28.3 // indirect - k8s.io/component-base v0.28.4 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/kubectl v0.28.4 // indirect - k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect - oras.land/oras-go v1.2.4 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect -) diff --git a/deploy/k8s-operator/kube-trailblazer/go.sum b/deploy/k8s-operator/kube-trailblazer/go.sum deleted file mode 100644 index b594b8361..000000000 --- a/deploy/k8s-operator/kube-trailblazer/go.sum +++ /dev/null @@ -1,590 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= -github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/hcsshim v0.11.0 h1:7EFNIY4igHEXUdj1zXgAyU3fLc7QfOKHbkldRVTBdiM= -github.com/Microsoft/hcsshim v0.11.0/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/changkun/lockfree v0.0.1 h1:5WefVJLglY4IHRqOQmh6Ao6wkJYaJkarshKU8VUtId4= -github.com/changkun/lockfree v0.0.1/go.mod h1:3bKiaXn/iNzIPlSvSOMSVbRQUQtAp8qUAyBUtzU11s4= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/containerd v1.7.6 h1:oNAVsnhPoy4BTPQivLgTzI9Oleml9l/+eYIDYXRCYo8= -github.com/containerd/containerd v1.7.6/go.mod h1:SY6lrkkuJT40BVNO37tlYTSnKJnP5AXBc0fhx0q+TJ4= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= -github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= -github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= -github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= -github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= -github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= -github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= -github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= -github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= -github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= -github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= -github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= -github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/openshift-psap/special-resource-operator v0.0.0-20220818111522-5e97683a2041 h1:7Hrj7tgy1phUDhXYHgzvEbwC88OAhxvuMVOwjZGTiLg= -github.com/openshift-psap/special-resource-operator v0.0.0-20220818111522-5e97683a2041/go.mod h1:SLNy0FiA4IEd9YTCIDnydsyIV7BBKzK5D+KZuoTfyc0= -github.com/openshift/api v0.0.0-20231128111040-e1845c5a7acd h1:bkX3IPDizf3+oYTIn10KbSIHTCsns1Ov6Ilv86Vm+Yc= -github.com/openshift/api v0.0.0-20231128111040-e1845c5a7acd/go.mod h1:qNtV0315F+f8ld52TLtPvrfivZpdimOzTi3kn9IVbtU= -github.com/openshift/client-go v0.0.0-20231121143148-910ca30a1a9a h1:4FVrw8hz0Wb3izbf6JfOEK+pJTYpEvteRR73mCh2g/A= -github.com/openshift/client-go v0.0.0-20231121143148-910ca30a1a9a/go.mod h1:arApQobmOjZqtxw44TwnQdUCH+t9DgZ8geYPFqksHws= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= -github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= -github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= -golang.design/x/lockfree v0.0.1 h1:IHFNwZgM5bnZYWkEbzn5lWHMYr8WsRBdCJ/RBVY0xMM= -golang.design/x/lockfree v0.0.1/go.mod h1:iaZUx6UgZaOdePjzI6wFd+seYMl1i0rsG8+xKvA8c4I= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -helm.sh/helm/v3 v3.13.2 h1:IcO9NgmmpetJODLZhR3f3q+6zzyXVKlRizKFwbi7K8w= -helm.sh/helm/v3 v3.13.2/go.mod h1:GIHDwZggaTGbedevTlrQ6DB++LBN6yuQdeGj0HNaDx0= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= -k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/apiserver v0.28.3 h1:8Ov47O1cMyeDzTXz0rwcfIIGAP/dP7L8rWbEljRcg5w= -k8s.io/apiserver v0.28.3/go.mod h1:YIpM+9wngNAv8Ctt0rHG4vQuX/I5rvkEMtZtsxW2rNM= -k8s.io/cli-runtime v0.28.4 h1:IW3aqSNFXiGDllJF4KVYM90YX4cXPGxuCxCVqCD8X+Q= -k8s.io/cli-runtime v0.28.4/go.mod h1:MLGRB7LWTIYyYR3d/DOgtUC8ihsAPA3P8K8FDNIqJ0k= -k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= -k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= -k8s.io/component-base v0.28.4 h1:c/iQLWPdUgI90O+T9TeECg8o7N3YJTiuz2sKxILYcYo= -k8s.io/component-base v0.28.4/go.mod h1:m9hR0uvqXDybiGL2nf/3Lf0MerAfQXzkfWhUY58JUbU= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/kubectl v0.28.4 h1:gWpUXW/T7aFne+rchYeHkyB8eVDl5UZce8G4X//kjUQ= -k8s.io/kubectl v0.28.4/go.mod h1:CKOccVx3l+3MmDbkXtIUtibq93nN2hkDR99XDCn7c/c= -k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= -k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= -oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= -sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= -sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/deploy/k8s-operator/kube-trailblazer/hack/boilerplate.go.txt b/deploy/k8s-operator/kube-trailblazer/hack/boilerplate.go.txt deleted file mode 100644 index 65b862271..000000000 --- a/deploy/k8s-operator/kube-trailblazer/hack/boilerplate.go.txt +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/global-values.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/global-values.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/.helmignore b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/Chart.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/Chart.yaml deleted file mode 100644 index 1dea245bb..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/Chart.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v2 -name: developer-llm-operator -description: A Helm chart for Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "0.1.0" diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0001_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0001_operator_manifests.yaml deleted file mode 100644 index 6b945d8a2..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0001_operator_manifests.yaml +++ /dev/null @@ -1,201 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null - name: helmpipelines.package.nvidia.com -spec: - group: package.nvidia.com - names: - kind: HelmPipeline - listKind: HelmPipelineList - plural: helmpipelines - singular: helmpipeline - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: HelmPipeline is the Schema for the helmpipelines API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: HelmPipelineSpec defines the desired state of HelmPipeline - properties: - managementState: - pattern: ^(Managed|Unmanaged|Force|Removed)$ - type: string - pipeline: - description: 'Orchard: A planned and managed group of Helm trees.' - items: - description: A shelter of vines or branches or of latticework covered with climbing shrubs or vines, also latin for tree - properties: - chartSpec: - properties: - atomic: - description: Atomic indicates whether to install resources atomically. 'Wait' will automatically be set to true when using Atomic. - type: boolean - chart: - type: string - cleanupOnFail: - description: CleanupOnFail indicates whether to cleanup the release on failure. - type: boolean - createNamespace: - description: CreateNamespace indicates whether to create the namespace if it does not exist. - type: boolean - dependencyUpdate: - description: DependencyUpdate indicates whether to update the chart release if the dependencies have changed. - type: boolean - description: - description: Description specifies a custom description for the uninstalled release - type: string - disableHooks: - description: DisableHooks indicates whether to disable hooks. - type: boolean - dryRun: - description: DryRun indicates whether to perform a dry run. - type: boolean - force: - description: Force indicates whether to force the operation. - type: boolean - generateName: - description: GenerateName indicates that the release name should be generated. - type: boolean - keepHistory: - description: KeepHistory indicates whether to retain or purge the release history during uninstall - type: boolean - maxHistory: - description: MaxHistory limits the maximum number of revisions saved per release. - type: integer - nameTemplate: - description: NameTemplate is the template used to generate the release name if GenerateName is configured. - type: string - namespace: - description: Namespace where the chart release is deployed. Note that helmclient.Options.Namespace should ideally match the namespace configured here. - type: string - recreate: - description: Recreate indicates whether to recreate the release if it already exists. - type: boolean - release: - type: string - replace: - description: Replace indicates whether to replace the chart release if it already exists. - type: boolean - resetValues: - description: ResetValues indicates whether to reset the values.yaml file during installation. - type: boolean - reuseValues: - description: ReuseValues indicates whether to reuse the values.yaml file during installation. - type: boolean - skipCRDs: - description: SkipCRDs indicates whether to skip CRDs during installation. - type: boolean - subNotes: - description: SubNotes indicates whether to print sub-notes. - type: boolean - timeout: - description: Timeout configures the time to wait for any individual Kubernetes operation (like Jobs for hooks). - format: int64 - type: integer - upgradeCRDs: - description: Upgrade indicates whether to perform a CRD upgrade during installation. - type: boolean - valuesOptions: - description: Specify values similar to the cli - properties: - JSONValues: - items: - type: string - type: array - fileValues: - items: - type: string - type: array - strinValues: - items: - type: string - type: array - valueFiles: - items: - type: string - type: array - values: - items: - type: string - type: array - required: - - JSONValues - - fileValues - - strinValues - - valueFiles - - values - type: object - valuesYaml: - description: ValuesYaml is the values.yaml content. use string instead of map[string]interface{} https://github.com/kubernetes-sigs/kubebuilder/issues/528#issuecomment-466449483 and https://github.com/kubernetes-sigs/controller-tools/pull/317 - type: string - version: - description: Version of the chart release. - type: string - wait: - description: Wait indicates whether to wait for the release to be deployed or not. - type: boolean - waitForJobs: - description: WaitForJobs indicates whether to wait for completion of release Jobs before marking the release as successful. 'Wait' has to be specified for this to take effect. The timeout may be specified via the 'Timeout' field. - type: boolean - required: - - chart - type: object - chartValues: - description: TODO ChartValues json.RawMessage `json:"chartValues"` - type: object - x-kubernetes-preserve-unknown-fields: true - releaseName: - type: string - repoEntry: - description: Entry represents a collection of parameters for chart repository, since we cannot annotate the internal helm struct we're doing it here - properties: - caFile: - type: string - certFile: - type: string - insecure_skip_tls_verify: - type: boolean - keyFile: - type: string - name: - type: string - pass_credentials_all: - type: boolean - password: - type: string - url: - type: string - username: - type: string - required: - - url - type: object - required: - - chartSpec - - repoEntry - type: object - type: array - required: - - pipeline - type: object - status: - description: HelmPipelineStatus defines the observed state of HelmPipeline - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0002_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0002_operator_manifests.yaml deleted file mode 100644 index 88ed3ac36..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0002_operator_manifests.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: controller-manager - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: serviceaccount - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-controller-manager - namespace: {{ .Release.Namespace }} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0003_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0003_operator_manifests.yaml deleted file mode 100644 index 6080cb991..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0003_operator_manifests.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: leader-election-role - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: role - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-leader-election-role - namespace: kube-trailblazer-system -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0004_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0004_operator_manifests.yaml deleted file mode 100644 index 6a8509e5d..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0004_operator_manifests.yaml +++ /dev/null @@ -1,1227 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: kube-trailblazer-manager-role -rules: -- apiGroups: - - "" - resources: - - nodes/finalizers - verbs: - - update -- apiGroups: - - "" - resources: - - nodes/proxy - verbs: - - get -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - get - - list - - patch - - update -- apiGroups: - - "" - resources: - - pods - verbs: - - deletecollection -- apiGroups: - - "" - resources: - - podtemplates - verbs: - - create - - get - - list - - update - - watch -- apiGroups: - - "" - resources: - - podtemplates/finalizers - verbs: - - update -- apiGroups: - - '*' - resources: - - cronjobs - verbs: - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - '*' - resources: - - daemonsets - verbs: - - get -- apiGroups: - - '*' - resources: - - deployments - verbs: - - get -- apiGroups: - - '*' - resources: - - imagepolicies - verbs: - - delete - - get - - update -- apiGroups: - - '*' - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - '*' - resources: - - mutatingwebhookconfigurations - verbs: - - get -- apiGroups: - - '*' - resources: - - pods - verbs: - - get -- apiGroups: - - '*' - resources: - - replicacontrollers - verbs: - - get -- apiGroups: - - '*' - resources: - - replicasets - verbs: - - get -- apiGroups: - - '*' - resources: - - statefulsets - verbs: - - get -- apiGroups: - - acme.cert-manager.io - resources: - - challenges - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - acme.cert-manager.io - resources: - - challenges/finalizers - verbs: - - update -- apiGroups: - - acme.cert-manager.io - resources: - - challenges/status - verbs: - - update -- apiGroups: - - acme.cert-manager.io - resources: - - orders - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - acme.cert-manager.io - resources: - - orders/finalizers - verbs: - - update -- apiGroups: - - acme.cert-manager.io - resources: - - orders/status - verbs: - - update -- apiGroups: - - admissionregistration.k8s.io - resources: - - mutatingwebhookconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - admissionregistration.k8s.io - resources: - - validatingwebhookconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - admissionregistration.k8s.io/v1beta1 - resources: - - mutatingwebhookconfigurations - verbs: - - create - - delete - - list - - update -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apiregistration.k8s.io - resources: - - apiservices - verbs: - - get - - list - - update - - watch -- apiGroups: - - apps - resources: - - daemonsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resourceNames: - - shipwright-build - resources: - - deployments/finalizers - verbs: - - update -- apiGroups: - - apps - resources: - - replicasets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - auditregistration.k8s.io - resources: - - auditsinks - verbs: - - get - - list - - update - - watch -- apiGroups: - - batch - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - batch - resources: - - jobs/finalizers - verbs: - - update -- apiGroups: - - build.openshift.io - resources: - - buildconfigs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - build.openshift.io - resources: - - builds - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - certificaterequests - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - certificaterequests/finalizers - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - certificaterequests/status - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - certificates - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - certificates/finalizers - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - certificates/status - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - clusterissuers - verbs: - - deletecollection - - get - - list - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - clusterissuers/status - verbs: - - update -- apiGroups: - - cert-manager.io - resources: - - issuers - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - cert-manager.io - resources: - - issuers/status - verbs: - - update -- apiGroups: - - cert-manager.io - resourceNames: - - clusterissuers.cert-manager.io/* - resources: - - signers - verbs: - - approve -- apiGroups: - - cert-manager.io - resourceNames: - - issuers.cert-manager.io/* - resources: - - signers - verbs: - - approve -- apiGroups: - - certificates.k8s.io - resources: - - certificatesigningrequests - verbs: - - get - - list - - update - - watch -- apiGroups: - - certificates.k8s.io - resources: - - certificatesigningrequests/status - verbs: - - update -- apiGroups: - - certificates.k8s.io - resourceNames: - - clusterissuers.cert-manager.io/* - resources: - - signers - verbs: - - sign -- apiGroups: - - certificates.k8s.io - resourceNames: - - issuers.cert-manager.io/* - resources: - - signers - verbs: - - sign -- apiGroups: - - config.openshift.io - resources: - - clusterversions - verbs: - - get -- apiGroups: - - config.openshift.io - resources: - - proxies - verbs: - - get - - list -- apiGroups: - - connaisseur.policy - resources: - - imagepolicies - verbs: - - create -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-cainjector-election-core - resources: - - leases - verbs: - - patch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-cainjector-leader-election - resources: - - leases - verbs: - - patch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-cainjector-leader-election-core - resources: - - leases - verbs: - - patch -- apiGroups: - - coordination.k8s.io - resourceNames: - - cert-manager-controller - resources: - - leases - verbs: - - patch -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - imagestreams/layers - verbs: - - get -- apiGroups: - - "" - resources: - - namespaces - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims/status - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - pods - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - pods/log - verbs: - - get -- apiGroups: - - "" - resources: - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - services/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - csi.storage.k8s.io - resources: - - csidrivers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - extensions - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - fpga.silicom.dk - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - image.openshift.io - resources: - - imagestreams - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - image.openshift.io - resources: - - imagestreams/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - image.openshift.io - resources: - - imagestreams/layers - verbs: - - get -- apiGroups: - - infoscale.veritas.com - resources: - - infoscaleclusters - verbs: - - get - - list - - patch - - update -- apiGroups: - - monitoring.coreos.com - resources: - - prometheusrules - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - networking.k8s.io - resources: - - clustercidrs - verbs: - - list - - watch -- apiGroups: - - networking.k8s.io - resources: - - ingresses - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - networking.k8s.io - resources: - - ingresses/finalizers - verbs: - - update -- apiGroups: - - networking.x-k8s.io - resources: - - gateways - verbs: - - get - - list - - watch -- apiGroups: - - networking.x-k8s.io - resources: - - gateways/finalizers - verbs: - - update -- apiGroups: - - networking.x-k8s.io - resources: - - httproutes - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - networking.x-k8s.io - resources: - - httproutes/finalisers - verbs: - - update -- apiGroups: - - nfd.k8s-sigs.io - resources: - - nodefeaturerules - verbs: - - get - - list - - watch -- apiGroups: - - nfd.k8s-sigs.io - resources: - - nodefeatures - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - nvidia.com - resources: - - clusterpolicies - verbs: - - get - - list - - patch - - watch -- apiGroups: - - operator.cert-manager.io - resources: - - certmanagers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - operators.coreos.com - resources: - - operatorgroups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - operators.coreos.com - resources: - - subscriptions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines/finalizers - verbs: - - update -- apiGroups: - - package.nvidia.com - resources: - - helmpipelines/status - verbs: - - get - - patch - - update -- apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterrolebindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterroles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - route.openshift.io - resources: - - routes/custom-host - verbs: - - create -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - create - - delete - - get - - list - - patch - - update - - use - - watch -- apiGroups: - - shipwright.io - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - shipwright.io - resources: - - buildruns - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - shipwright.io - resources: - - buildstrategies - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - shipwright.io - resources: - - clusterbuildstrategies - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotclasses - verbs: - - get - - list - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents/status - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshots - verbs: - - get - - list - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshots/status - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - sro.openshift.io - resources: - - specialresources - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - sro.openshift.io - resources: - - specialresources/finalizers - verbs: - - get - - patch - - update -- apiGroups: - - sro.openshift.io - resources: - - specialresources/status - verbs: - - get - - patch - - update -- apiGroups: - - storage.k8s.io - resources: - - csidrivers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - storage.k8s.io - resources: - - csinodes - verbs: - - get - - list - - watch -- apiGroups: - - storage.k8s.io - resources: - - storageclasses - verbs: - - get - - list - - watch -- apiGroups: - - storage.k8s.io - resources: - - volumeattachments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - sts.silicom.com - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - tekton.dev - resources: - - taskruns - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - tekton.dev - resources: - - tasks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - topology.node.k8s.io - resources: - - noderesourcetopologies - verbs: - - delete - - list diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0005_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0005_operator_manifests.yaml deleted file mode 100644 index c66e93e3f..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0005_operator_manifests.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: metrics-reader - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrole - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-metrics-reader -rules: -- nonResourceURLs: - - /metrics - verbs: - - get diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0006_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0006_operator_manifests.yaml deleted file mode 100644 index 238d975f5..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0006_operator_manifests.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: proxy-role - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrole - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-proxy-role -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0007_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0007_operator_manifests.yaml deleted file mode 100644 index 09bc970a4..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0007_operator_manifests.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: leader-election-rolebinding - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: rolebinding - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-leader-election-rolebinding - namespace: {{ .Release.Namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: kube-trailblazer-leader-election-role -subjects: -- kind: ServiceAccount - name: kube-trailblazer-controller-manager - namespace: {{ .Release.Namespace }} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0008_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0008_operator_manifests.yaml deleted file mode 100644 index 2fd15af61..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0008_operator_manifests.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: manager-rolebinding - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-trailblazer-manager-role -subjects: -- kind: ServiceAccount - name: kube-trailblazer-controller-manager - namespace: {{ .Release.Namespace }} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0009_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0009_operator_manifests.yaml deleted file mode 100644 index 083907701..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0009_operator_manifests.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: proxy-rolebinding - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/part-of: kube-trailblazer - name: kube-trailblazer-proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-trailblazer-proxy-role -subjects: -- kind: ServiceAccount - name: kube-trailblazer-controller-manager - namespace: {{ .Release.Namespace }} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0010_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0010_operator_manifests.yaml deleted file mode 100644 index b8c0afb53..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0010_operator_manifests.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: controller-manager-metrics-service - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: service - app.kubernetes.io/part-of: kube-trailblazer - control-plane: controller-manager - name: kube-trailblazer-controller-manager-metrics-service - namespace: {{ .Release.Namespace }} -spec: - ports: - - name: https - port: 8443 - protocol: TCP - targetPort: https - selector: - control-plane: controller-manager diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0011_operator_manifests.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0011_operator_manifests.yaml deleted file mode 100644 index 6541ce594..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/0011_operator_manifests.yaml +++ /dev/null @@ -1,106 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: kube-trailblazer - app.kubernetes.io/instance: controller-manager - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: deployment - app.kubernetes.io/part-of: kube-trailblazer - control-plane: controller-manager - name: kube-trailblazer-controller-manager - namespace: {{ .Release.Namespace }} -spec: - replicas: 1 - selector: - matchLabels: - control-plane: controller-manager - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - labels: - control-plane: controller-manager - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - arm64 - - ppc64le - - s390x - - key: kubernetes.io/os - operator: In - values: - - linux - containers: - - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=0 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1 - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: https - protocol: TCP - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 5m - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - - args: - - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 - - --leader-elect - command: - - /manager - image: {{ include "developer-llm-operator.fullimage" . }} - imagePullPolicy: {{ .Values.images.imagePullPolicy }} - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - name: manager - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 100m - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - {{- if .Values.images.registry.imagePullSecret.name }} - imagePullSecrets: - - name: {{ .Values.images.registry.imagePullSecret.name }} - {{- end }} - securityContext: - runAsNonRoot: true - serviceAccountName: kube-trailblazer-controller-manager - terminationGracePeriodSeconds: 10 diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/_helpers.tpl b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/_helpers.tpl deleted file mode 100644 index d49dd2982..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/_helpers.tpl +++ /dev/null @@ -1,17 +0,0 @@ -{{/* -Create secret to access docker registry -*/}} -{{- define "imagePullSecret" }} -{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.images.registry.name (printf "%s:%s" .Values.images.registry.imagePullSecret.username .Values.images.registry.imagePullSecret.password | b64enc) | b64enc }} -{{- end }} - -{{/* -Full image name with tag -*/}} -{{- define "developer-llm-operator.fullimage" -}} -{{- if .Values.images.version }} -{{- .Values.images.name -}}:{{- .Values.images.version -}} -{{- else }} -{{- .Values.images.name -}}:v{{- .Chart.AppVersion -}} -{{- end }} -{{- end }} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/image-pull-secret.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/image-pull-secret.yaml deleted file mode 100644 index e526dbe55..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/templates/image-pull-secret.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{ if and .Values.images.registry.imagePullSecret.name .Values.images.registry.imagePullSecret.create -}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Values.images.registry.imagePullSecret.name }} - namespace: {{ .Release.Namespace }} -type: kubernetes.io/dockerconfigjson -data: - .dockerconfigjson: {{ template "imagePullSecret" . }} -{{- end }} \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/values.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/values.yaml deleted file mode 100644 index 87b55d73b..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/developer-llm-operator/values.yaml +++ /dev/null @@ -1,19 +0,0 @@ -images: - # operator image name - name: nvcr.io/nvidia/cloud-native/developer-llm-operator - # operator image version. If empty then the chart's app-version is used as default - version: "" - imagePullPolicy: IfNotPresent - # operator registry details for pull-secret - registry: - # The registry name must NOT contain a trailing slash - name: nvcr.io - imagePullSecret: - # Leave blank, if no imagePullSecret is needed. - name: "" - # If set to false, the chart expects either a imagePullSecret - # with the name configured above to be present on the cluster or that no - # credentials are needed. - create: true - username: '$oauthtoken' - password: "" \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/.helmignore b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/Chart.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/Chart.yaml deleted file mode 100644 index b73ea5fe7..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -appVersion: 1.16.0 -description: A Helm chart for Kubernetes -name: rag-llm-pipeline -type: application -version: 0.1.0 diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/_helpers.tpl b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/_helpers.tpl deleted file mode 100644 index 391efe261..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/_helpers.tpl +++ /dev/null @@ -1,6 +0,0 @@ -{{/* -Create secret to access docker registry -*/}} -{{- define "imagePullSecret" }} -{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.images.registry.name (printf "%s:%s" .Values.images.registry.ImagePullSecret.username .Values.images.registry.ImagePullSecret.password | b64enc) | b64enc }} -{{- end }} diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/frontend.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/frontend.yaml deleted file mode 100644 index bd1940def..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/frontend.yaml +++ /dev/null @@ -1,52 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: llm-playground - labels: - app.kubernetes.io/name: frontend -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: frontend - template: - metadata: - labels: - app.kubernetes.io/name: frontend - spec: - - imagePullSecrets: - - name: nvcrio - containers: - - name: llm-playground - imagePullPolicy: IfNotPresent - image: {{ .Values.frontend.image }} - command: - - python3 - - -m - - frontend - - --port - - "8090" - env: - - name: APP_MODELNAME - value: {{ .Values.frontend.modelName }} - - name: APP_SERVERPORT - value: "8081" - - name: APP_SERVERURL - value: http://query - ports: - - containerPort: 8090 ---- -apiVersion: v1 -kind: Service -metadata: - name: frontend-service -spec: - type: NodePort - selector: - app.kubernetes.io/name: frontend - ports: - - protocol: TCP - port: 8090 - nodePort: 30001 - \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/image-pull-secret.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/image-pull-secret.yaml deleted file mode 100644 index d1074724d..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/image-pull-secret.yaml +++ /dev/null @@ -1,9 +0,0 @@ -{{ if and .Values.images.registry.ImagePullSecret.name .Values.images.registry.ImagePullSecret.create -}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Values.images.registry.ImagePullSecret.name }} -type: kubernetes.io/dockerconfigjson -data: - .dockerconfigjson: {{ template "imagePullSecret" . }} -{{- end }} \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/jupyter-server.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/jupyter-server.yaml deleted file mode 100644 index e2c71fea8..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/jupyter-server.yaml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: jupyter-notebook-server - labels: - app.kubernetes.io/name: jupyter-notebook-server -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: jupyter-notebook-server - template: - metadata: - labels: - app.kubernetes.io/name: jupyter-notebook-server - spec: - imagePullSecrets: - - name: nvcrio - containers: - - name: jupyter-notebook-server - imagePullPolicy: IfNotPresent - image: {{ .Values.jupyter.image }} - ports: - - containerPort: 8888 - resources: - limits: - {{ .Values.jupyter.gpu.type }}: {{ .Values.jupyter.gpu.count }} ---- -apiVersion: v1 -kind: Service -metadata: - name: jupyter-notebook-service -spec: - type: NodePort - - selector: - app.kubernetes.io/name: jupyter-notebook-server - ports: - - protocol: TCP - port: 8888 - nodePort: 30000 \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-etcd.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-etcd.yaml deleted file mode 100644 index dde20b762..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-etcd.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: milvu-etcd - labels: - app.kubernetes.io/name: milvus-etcd -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: milvus-etcd - template: - metadata: - labels: - app.kubernetes.io/name: milvus-etcd - spec: - containers: - - name: milvus-etcd - image: quay.io/coreos/etcd:v3.5.5 - command: - - etcd - - -advertise-client-urls=http://127.0.0.1:2379 - - -listen-client-urls - - http://0.0.0.0:2379 - - --data-dir - - /etcd - env: - - name: ETCD_AUTO_COMPACTION_MODE - value: revision - - name: ETCD_AUTO_COMPACTION_RETENTION - value: "1000" - - name: ETCD_QUOTA_BACKEND_BYTES - value: "4294967296" - - name: ETCD_SNAPSHOT_COUNT - value: "50000" - ports: - - containerPort: 2379 - readinessProbe: - exec: - command: - - etcdctl - - endpoint - - health - initialDelaySeconds: 5 - periodSeconds: 5 - volumeMounts: - - mountPath: /etcd - name: etcd-data - volumes: - - name: etcd-data - hostPath: - path: /etcd - type: DirectoryOrCreate ---- -apiVersion: v1 -kind: Service -metadata: - name: milvus-etcd -spec: - selector: - app.kubernetes.io/name: milvus-etcd - ports: - - protocol: TCP - port: 2379 - targetPort: 2379 \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-minio.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-minio.yaml deleted file mode 100644 index fc302398e..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-minio.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: milvus-minio - labels: - app.kubernetes.io/name: milvus-minio -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: milvus-minio - template: - metadata: - labels: - app.kubernetes.io/name: milvus-minio - spec: - containers: - - name: milvus-minio - image: minio/minio:RELEASE.2023-03-20T20-16-18Z - command: - - minio - - server - - /minio_data - - --console-address - - :9011 - env: - - name: MINIO_ACCESS_KEY - value: minioadmin - - name: MINIO_SECRET_KEY - value: minioadmin - ports: - - containerPort: 9011 - - containerPort: 9010 - volumeMounts: - - mountPath: /minio_data - name: minio-data - readinessProbe: - exec: - command: - - curl - - -f - - http://localhost:9010/minio/health/live - initialDelaySeconds: 20 - periodSeconds: 5 - volumes: - - name: minio-data - hostPath: - path: /minio_data - type: DirectoryOrCreate ---- -apiVersion: v1 -kind: Service -metadata: - name: milvus-minio -spec: - selector: - app.kubernetes.io/name: milvus-minio - ports: - - protocol: TCP - port: 9010 - targetPort: 9010 - diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-standalone.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-standalone.yaml deleted file mode 100644 index a52bd916a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/milvus-standalone.yaml +++ /dev/null @@ -1,58 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: milvus-standalone - labels: - app.kubernetes.io/name: milvus-standalone -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: milvus-standalone - template: - metadata: - labels: - app.kubernetes.io/name: milvus-standalone - spec: - containers: - - name: milvus-standalone - image: milvusdb/milvus:v2.3.1-gpu - command: - - /tini - - -- - - milvus - - run - - standalone - env: - - name: ETCD_ENDPOINTS - value: milvus-etcd:2379 - - name: KNOWHERE_GPU_MEM_POOL_SIZE - value: 2048;4096 - - name: MINIO_ADDRESS - value: milvus-minio:9010 - ports: - - containerPort: 19530 - - containerPort: 9091 - readinessProbe: - exec: - command: - - curl - - -f - - http://localhost:9091/healthz - initialDelaySeconds: 20 - periodSeconds: 5 - resources: - limits: - {{ .Values.milvus.gpu.type }}: {{ .Values.milvus.gpu.count }} ---- -apiVersion: v1 -kind: Service -metadata: - name: milvus -spec: - selector: - app.kubernetes.io/name: milvus-standalone - ports: - - protocol: TCP - port: 19530 - targetPort: 19530 diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/query.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/query.yaml deleted file mode 100644 index d4ad9f3ca..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/query.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: query-router - labels: - app.kubernetes.io/name: query-router -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: query-router - template: - metadata: - labels: - app.kubernetes.io/name: query-router - spec: - - imagePullSecrets: - - name: nvcrio - volumes: - - name: dshm - emptyDir: - medium: Memory - containers: - - name: query-router - imagePullPolicy: IfNotPresent - image: {{ .Values.query.image }} - command: - - uvicorn - - RetrievalAugmentedGeneration.common.server:app - - --port - - "8081" - - --host - - 0.0.0.0 - env: - - name: APP_MILVUS_URL - value: http://milvus:19530 - - name: APP_LLM_SERVERURL - value: llm:8001 - - name: APP_LLM_MODELNAME - value: ensemble - - name: APP_LLM_MODELENGINE - value: triton-trt-llm -# - name: APP_CONFIG_FILE # THIS SHOULD BE A CONFIGMAP -# value: "" - ports: - - containerPort: 8081 - volumeMounts: - - mountPath: /dev/shm - name: dshm - resources: - limits: - {{ .Values.query.gpu.type }}: {{ .Values.query.gpu.count }} ---- -apiVersion: v1 -kind: Service -metadata: - name: query -spec: - selector: - app.kubernetes.io/name: query-router - ports: - - protocol: TCP - port: 8081 - targetPort: 8081 \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/triton.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/triton.yaml deleted file mode 100644 index 20b8ba57d..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/templates/triton.yaml +++ /dev/null @@ -1,86 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: triton-entrypoint -data: - entrypoint.sh: |- - #!/bin/bash -x - set -e - - rm -rf /usr/local/cuda-12.2/targets/x86_64-linux/lib/stubs/ - ldconfig - - /usr/bin/python3 -m model_server {{ .Values.triton.modelArchitecture | quote }} \ - --max-input-length {{ .Values.triton.modelMaxInputLength | quote}} \ - --max-output-length {{ .Values.triton.modelMaxOutputLength | quote}} - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: triton-inference-server - labels: - app.kubernetes.io/name: triton-inference-server -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: triton-inference-server - template: - metadata: - name: triton-inference-server - labels: - app.kubernetes.io/name: triton-inference-server - spec: - imagePullSecrets: - - name: nvcrio - containers: - - name: triton-inference-server - imagePullPolicy: IfNotPresent - image: {{ .Values.triton.image }} - command: [/bin/entrypoint.sh] - ports: - - containerPort: 8000 - - containerPort: 8001 - - containerPort: 8002 - readinessProbe: - grpc: - port: 8001 - initialDelaySeconds: 30 - periodSeconds: 10 - resources: - limits: - {{ .Values.triton.gpu.type }}: {{ .Values.triton.gpu.count }} - volumeMounts: - - mountPath: /model - name: model - - mountPath: /dev/shm - name: dshm - - name: entrypoint - mountPath: /bin/entrypoint.sh - readOnly: true - subPath: entrypoint.sh - volumes: - - name: model - hostPath: - path: {{ .Values.triton.modelDirectory }} - - name: dshm - emptyDir: - medium: Memory - - name: entrypoint - configMap: - defaultMode: 0700 - name: triton-entrypoint ---- -apiVersion: v1 -kind: Service -metadata: - name: llm -spec: - selector: - app.kubernetes.io/name: triton-inference-server - ports: - - protocol: TCP - port: 8001 - targetPort: 8001 - diff --git a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/values.yaml b/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/values.yaml deleted file mode 100644 index 8fa8abcf8..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-charts/staging/rag-llm-pipeline/values.yaml +++ /dev/null @@ -1,56 +0,0 @@ -# Default values for rag-llm-hackfest. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. -triton: - modelDirectory: "/zvonkok/model/llama2_13b_chat_hf_v1/" - modelArchitecture: "llama" - modelMaxInputLength: "3000" - modelMaxOutputLength: "512" - image: localhost:5000/llm-inference-server - gpu: - # MIG slice - #type: "nvidia.com/mig-3g.40gb" - # time-slice - type: "nvidia.com/gpu" - count: 1 - -milvus: - gpu: - # MIG slice - #type: "nvidia.com/mig-2g.20gb" - type: "nvidia.com/gpu" - count: 1 - -jupyter: - image: localhost:5000/notebook-server - gpu: - # MIG slice - # type: "nvidia.com/mig-1g.10gb" - type: "nvidia.com/gpu" - count: 1 - -query: - image: localhost:5000/chain-server - gpu: - # MIG slice - # type: "nvidia.com/mig-1g.10gb" - type: "nvidia.com/gpu" - count: 1 - -frontend: - image: localhost:5000/llm-playground - modelName: "Llama-2-13b-chat-hf" - -images: - registry: - # The registry name must NOT contain a trailing slash - name: nvcr.io - ImagePullSecret: - # Leave blank, if no ImagePullSecret is needed. - name: nvcrio - # If set to false, the chart expects either a ImagePullSecret - # with the name configured above to be present on the cluster or that no - # credentials are needed. - create: false - username: '$oauthtoken' - password: \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/helm-plugins/cm-getter/plugin.yaml b/deploy/k8s-operator/kube-trailblazer/helm-plugins/cm-getter/plugin.yaml deleted file mode 100644 index 4b78c4dda..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-plugins/cm-getter/plugin.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: cm-getter -version: 0.0.1 -description: cm:// Helm getter for ConfigMap charts -downloaders: -- command: cm-getter - protocols: [cm, configmap] diff --git a/deploy/k8s-operator/kube-trailblazer/helm-plugins/file-getter/file-getter b/deploy/k8s-operator/kube-trailblazer/helm-plugins/file-getter/file-getter deleted file mode 100755 index 216312d90..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-plugins/file-getter/file-getter +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -# Last command-line argument is the URL of the resource -readonly URL="${*: -1}" - -# Trim the scheme -readonly FILE="${URL#file://}" - -cat "${FILE}" diff --git a/deploy/k8s-operator/kube-trailblazer/helm-plugins/file-getter/plugin.yaml b/deploy/k8s-operator/kube-trailblazer/helm-plugins/file-getter/plugin.yaml deleted file mode 100644 index b5f6983a8..000000000 --- a/deploy/k8s-operator/kube-trailblazer/helm-plugins/file-getter/plugin.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: file-getter -version: 0.0.1 -description: file:// Helm getter for local filesystem charts -downloaders: -- command: file-getter - protocols: [file] diff --git a/deploy/k8s-operator/kube-trailblazer/main.go b/deploy/k8s-operator/kube-trailblazer/main.go deleted file mode 100644 index 376134fa8..000000000 --- a/deploy/k8s-operator/kube-trailblazer/main.go +++ /dev/null @@ -1,133 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "flag" - "os" - - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - _ "k8s.io/client-go/plugin/pkg/client/auth" - "k8s.io/klog/v2" - "k8s.io/klog/v2/klogr" - - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/healthz" - - packagev1alpha1 "github.com/nvidia/kube-trailblazer/api/v1alpha1" - "github.com/nvidia/kube-trailblazer/controllers" - "github.com/nvidia/kube-trailblazer/pkg/clients" - "github.com/nvidia/kube-trailblazer/pkg/filter" - //+kubebuilder:scaffold:imports -) - -var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") -) - -func init() { - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - - utilruntime.Must(packagev1alpha1.AddToScheme(scheme)) - //+kubebuilder:scaffold:scheme -} - -func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - - /*opts := zap.Options{ - Development: true, - } - opts.BindFlags(flag.CommandLine) - flag.Parse() - - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))*/ - - klog.InitFlags(nil) - flag.Parse() - - ctrl.SetLogger(klogr.New()) - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - //MetricsBindAddress: metricsAddr, - //Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "6673c020.nvidia.com", - // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily - // when the Manager ends. This requires the binary to immediately end when the - // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly - // speeds up voluntary leader transitions as the new leader don't have to wait - // LeaseDuration time first. - // - // In the default scaffold provided, the program ends immediately after - // the manager stops, so would be fine to enable this option. However, - // if you are doing or is intended to do any operation such as perform cleanups - // after the manager stops then its usage might be unsafe. - // LeaderElectionReleaseOnCancel: true, - }) - if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) - } - - kubeClient, err := clients.NewClients(mgr.GetClient(), mgr.GetConfig(), mgr.GetEventRecorderFor("specialresource")) - if err != nil { - setupLog.Error(err, "unable to create k8s clients") - os.Exit(1) - } - - if err = (&controllers.HelmPipelineReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Filter: filter.NewFilter(), - KubeClient: kubeClient, - RestConf: mgr.GetConfig(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "HelmPipeline") - os.Exit(1) - } - //+kubebuilder:scaffold:builder - - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") - os.Exit(1) - } - - setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/clients/clients.go b/deploy/k8s-operator/kube-trailblazer/pkg/clients/clients.go deleted file mode 100644 index ca774d34b..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/clients/clients.go +++ /dev/null @@ -1,252 +0,0 @@ -package clients - -import ( - "context" - "fmt" - - buildv1 "github.com/openshift/api/build/v1" - configv1 "github.com/openshift/api/config/v1" - clientconfigv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - "k8s.io/cli-runtime/pkg/genericclioptions" - - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" - "k8s.io/client-go/kubernetes" - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - controllerruntime "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -//go:generate mockgen -source=clients.go -package=clients -destination=mock_clients_api.go - -const ( - clusterVersionName = "version" -) - -var ( - // TODO need to remove this global variable - Namespace string -) - -type ClientsInterface interface { - Update(ctx context.Context, obj client.Object) error - Get(ctx context.Context, key client.ObjectKey, obj client.Object) error - Delete(ctx context.Context, obj client.Object) error - List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error - Create(ctx context.Context, obj client.Object) error - GetPodLogs(namespace, podName string, podLogOpts *v1.PodLogOptions) *restclient.Request - GetNamespace(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error) - GetSecret(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*v1.Secret, error) - ClusterVersionGet(ctx context.Context, opts metav1.GetOptions) (result *configv1.ClusterVersion, err error) - Invalidate() - ServerGroups() (*metav1.APIGroupList, error) - StatusUpdate(ctx context.Context, obj client.Object) error - CreateOrUpdate(ctx context.Context, obj client.Object, fn controllerutil.MutateFn) (controllerutil.OperationResult, error) - HasResource(resource schema.GroupVersionResource) (bool, error) - GetNodesByLabels(ctx context.Context, matchingLabels map[string]string) (*v1.NodeList, error) - GetPlatform() (string, error) -} - -type k8sClients struct { - runtimeClient client.Client - clientset kubernetes.Clientset - configV1Client clientconfigv1.ConfigV1Client - eventRecorder record.EventRecorder - cachedDiscovery discovery.CachedDiscoveryInterface - restConfig *restclient.Config -} - -func NewKubeClientsFromRestConf(restConfig *restclient.Config) (ClientsInterface, error) { - kubeClientSet, err := getKubeClientSet(restConfig) - if err != nil { - panic(err) - } - configClient, err := getConfigClient(restConfig) - if err != nil { - panic(err) - } - cachedDiscoveryClient, err := getCachedDiscoveryClient() - if err != nil { - panic(err) - } - - runtimeClient, err := client.New(restConfig, client.Options{}) - if err != nil { - panic(err) - } - - return &k8sClients{ - runtimeClient: runtimeClient, - clientset: *kubeClientSet, - configV1Client: *configClient, - eventRecorder: nil, - cachedDiscovery: cachedDiscoveryClient, - restConfig: restConfig, - }, nil -} - -func NewClients(runtimeClient client.Client, restConfig *restclient.Config, eventRecorder record.EventRecorder) (ClientsInterface, error) { - kubeClientSet, err := getKubeClientSet(restConfig) - if err != nil { - return nil, err - } - configClient, err := getConfigClient(restConfig) - if err != nil { - return nil, err - } - cachedDiscoveryClient, err := getCachedDiscoveryClient() - if err != nil { - return nil, err - } - return &k8sClients{ - runtimeClient: runtimeClient, - clientset: *kubeClientSet, - configV1Client: *configClient, - eventRecorder: eventRecorder, - cachedDiscovery: cachedDiscoveryClient, - restConfig: restConfig, - }, nil -} - -func (k *k8sClients) Update(ctx context.Context, obj client.Object) error { - return k.runtimeClient.Update(ctx, obj) -} - -func (k *k8sClients) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error { - return k.runtimeClient.Get(ctx, key, obj) -} - -func (k *k8sClients) Delete(ctx context.Context, obj client.Object) error { - return k.runtimeClient.Delete(ctx, obj) -} - -func (k *k8sClients) List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error { - return k.runtimeClient.List(ctx, obj, opts...) -} - -func (k *k8sClients) Create(ctx context.Context, obj client.Object) error { - return k.runtimeClient.Create(ctx, obj) -} - -func (k *k8sClients) GetPodLogs(namespace, podName string, podLogOpts *v1.PodLogOptions) *restclient.Request { - return k.clientset.CoreV1().Pods(namespace).GetLogs(podName, podLogOpts) -} - -func (k *k8sClients) GetNamespace(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error) { - return k.clientset.CoreV1().Namespaces().Get(ctx, name, opts) -} - -func (k *k8sClients) GetSecret(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*v1.Secret, error) { - return k.clientset.CoreV1().Secrets(namespace).Get(ctx, name, opts) -} - -func (k *k8sClients) ClusterVersionGet(ctx context.Context, opts metav1.GetOptions) (result *configv1.ClusterVersion, err error) { - return k.configV1Client.ClusterVersions().Get(ctx, clusterVersionName, opts) -} - -func (k *k8sClients) Invalidate() { - k.cachedDiscovery.Invalidate() -} - -func (k *k8sClients) ServerGroups() (*metav1.APIGroupList, error) { - return k.cachedDiscovery.ServerGroups() -} - -func (k *k8sClients) StatusUpdate(ctx context.Context, obj client.Object) error { - return k.runtimeClient.Status().Update(ctx, obj) -} - -func (k *k8sClients) CreateOrUpdate(ctx context.Context, obj client.Object, fn controllerutil.MutateFn) (controllerutil.OperationResult, error) { - return controllerruntime.CreateOrUpdate(ctx, k.runtimeClient, obj, fn) -} - -func (k *k8sClients) HasResource(resource schema.GroupVersionResource) (bool, error) { - dclient, err := discovery.NewDiscoveryClientForConfig(k.restConfig) - if err != nil { - return false, fmt.Errorf("Cannot retrieve a DiscoveryClient: %w", err) - } - if dclient == nil { - return false, nil - } - - resources, err := dclient.ServerResourcesForGroupVersion(resource.GroupVersion().String()) - if apierrors.IsNotFound(err) { - // entire group is missing - return false, nil - } - if err != nil { - return false, fmt.Errorf("Cannot query ServerResources: %w", err) - } else { - for _, serverResource := range resources.APIResources { - if serverResource.Name == resource.Resource { - //Found it - return true, nil - } - } - } - - return false, nil -} - -func (k *k8sClients) GetPlatform() (string, error) { - clusterIsOCP, err := k.HasResource(buildv1.SchemeGroupVersion.WithResource("buildconfigs")) - if err != nil { - return "", err - } - if clusterIsOCP { - return "OCP", nil - } else { - return "K8S", nil - } -} - -func (k *k8sClients) GetNodesByLabels(ctx context.Context, matchingLabels map[string]string) (*v1.NodeList, error) { - opts := []client.ListOption{ - client.MatchingLabels(matchingLabels), - } - nodes := v1.NodeList{} - err := k.runtimeClient.List(ctx, &nodes, opts...) - if err != nil { - return nil, err - } - - // filter nodes by taints - nodesWithoutTaints := nodes.Items[:0] - for _, node := range nodes.Items { - if k.isNodeNotExecOrSchedule(&node) { - continue - } - nodesWithoutTaints = append(nodesWithoutTaints, node) - } - nodes.Items = nodesWithoutTaints - return &nodes, nil -} - -func (k *k8sClients) isNodeNotExecOrSchedule(node *v1.Node) bool { - for _, taint := range node.Spec.Taints { - if taint.Effect == v1.TaintEffectNoSchedule || taint.Effect == v1.TaintEffectNoExecute { - return true - } - } - return false -} - -// getKubeClientSet returns a native non-caching client for advanced CRUD operations -func getKubeClientSet(restConfig *restclient.Config) (*kubernetes.Clientset, error) { - return kubernetes.NewForConfig(restConfig) -} - -// getConfigClient returns a configv1 client to the reconciler -func getConfigClient(restConfig *restclient.Config) (*clientconfigv1.ConfigV1Client, error) { - return clientconfigv1.NewForConfig(restConfig) -} - -func getCachedDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { - var config genericclioptions.ConfigFlags - return config.ToDiscoveryClient() -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/clients/clients_test.go b/deploy/k8s-operator/kube-trailblazer/pkg/clients/clients_test.go deleted file mode 100644 index b3821fe63..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/clients/clients_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package clients - -import ( - "context" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/openshift-psap/special-resource-operator/pkg/utils" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestPkgClients(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Clients Suite") -} - -var _ = Describe("GetNodesByLabels", func() { - type testInput struct { - numNodes int - labels map[string]string - addTaint bool - taintEffect corev1.TaintEffect - expectedNumNodes int - } - - DescribeTable( - "should return correct number of nodes", - func(test testInput) { - nodesList := utils.CreateNodesList(test.numNodes, test.labels) - if test.addTaint { - utils.SetTaint(&nodesList.Items[0], "taintKey", "taintValue", test.taintEffect) - } - objs := []runtime.Object{nodesList} - clientsStruct := k8sClients{runtimeClient: fake.NewClientBuilder().WithRuntimeObjects(objs...).Build()} - res, _ := clientsStruct.GetNodesByLabels(context.TODO(), test.labels) - Expect(res.Items).To(HaveLen(test.expectedNumNodes)) - }, - Entry( - "all nodes without taint", - testInput{ - numNodes: 3, - labels: map[string]string{"key1": "label1"}, - addTaint: false, - expectedNumNodes: 3, - }, - ), - Entry( - "a node with NoExecute taint", - testInput{ - numNodes: 3, - labels: map[string]string{"key1": "label1"}, - addTaint: true, - taintEffect: corev1.TaintEffectNoExecute, - expectedNumNodes: 2, - }, - ), - Entry( - "a node with NoSchedule taint", - testInput{ - numNodes: 3, - labels: map[string]string{"key1": "label1"}, - addTaint: true, - taintEffect: corev1.TaintEffectNoSchedule, - expectedNumNodes: 2, - }, - ), - ) -}) diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/clients/mock_clients_api.go b/deploy/k8s-operator/kube-trailblazer/pkg/clients/mock_clients_api.go deleted file mode 100644 index 30c04b745..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/clients/mock_clients_api.go +++ /dev/null @@ -1,277 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: clients.go - -// Package clients is a generated GoMock package. -package clients - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - v1 "github.com/openshift/api/config/v1" - v10 "k8s.io/api/core/v1" - v11 "k8s.io/apimachinery/pkg/apis/meta/v1" - schema "k8s.io/apimachinery/pkg/runtime/schema" - rest "k8s.io/client-go/rest" - client "sigs.k8s.io/controller-runtime/pkg/client" - controllerutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -// MockClientsInterface is a mock of ClientsInterface interface. -type MockClientsInterface struct { - ctrl *gomock.Controller - recorder *MockClientsInterfaceMockRecorder -} - -// MockClientsInterfaceMockRecorder is the mock recorder for MockClientsInterface. -type MockClientsInterfaceMockRecorder struct { - mock *MockClientsInterface -} - -// NewMockClientsInterface creates a new mock instance. -func NewMockClientsInterface(ctrl *gomock.Controller) *MockClientsInterface { - mock := &MockClientsInterface{ctrl: ctrl} - mock.recorder = &MockClientsInterfaceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockClientsInterface) EXPECT() *MockClientsInterfaceMockRecorder { - return m.recorder -} - -// ClusterVersionGet mocks base method. -func (m *MockClientsInterface) ClusterVersionGet(ctx context.Context, opts v11.GetOptions) (*v1.ClusterVersion, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ClusterVersionGet", ctx, opts) - ret0, _ := ret[0].(*v1.ClusterVersion) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ClusterVersionGet indicates an expected call of ClusterVersionGet. -func (mr *MockClientsInterfaceMockRecorder) ClusterVersionGet(ctx, opts interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterVersionGet", reflect.TypeOf((*MockClientsInterface)(nil).ClusterVersionGet), ctx, opts) -} - -// Create mocks base method. -func (m *MockClientsInterface) Create(ctx context.Context, obj client.Object) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", ctx, obj) - ret0, _ := ret[0].(error) - return ret0 -} - -// Create indicates an expected call of Create. -func (mr *MockClientsInterfaceMockRecorder) Create(ctx, obj interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockClientsInterface)(nil).Create), ctx, obj) -} - -// CreateOrUpdate mocks base method. -func (m *MockClientsInterface) CreateOrUpdate(ctx context.Context, obj client.Object, fn controllerutil.MutateFn) (controllerutil.OperationResult, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateOrUpdate", ctx, obj, fn) - ret0, _ := ret[0].(controllerutil.OperationResult) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateOrUpdate indicates an expected call of CreateOrUpdate. -func (mr *MockClientsInterfaceMockRecorder) CreateOrUpdate(ctx, obj, fn interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockClientsInterface)(nil).CreateOrUpdate), ctx, obj, fn) -} - -// Delete mocks base method. -func (m *MockClientsInterface) Delete(ctx context.Context, obj client.Object) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", ctx, obj) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockClientsInterfaceMockRecorder) Delete(ctx, obj interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClientsInterface)(nil).Delete), ctx, obj) -} - -// Get mocks base method. -func (m *MockClientsInterface) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", ctx, key, obj) - ret0, _ := ret[0].(error) - return ret0 -} - -// Get indicates an expected call of Get. -func (mr *MockClientsInterfaceMockRecorder) Get(ctx, key, obj interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockClientsInterface)(nil).Get), ctx, key, obj) -} - -// GetNamespace mocks base method. -func (m *MockClientsInterface) GetNamespace(ctx context.Context, name string, opts v11.GetOptions) (*v10.Namespace, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetNamespace", ctx, name, opts) - ret0, _ := ret[0].(*v10.Namespace) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetNamespace indicates an expected call of GetNamespace. -func (mr *MockClientsInterfaceMockRecorder) GetNamespace(ctx, name, opts interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNamespace", reflect.TypeOf((*MockClientsInterface)(nil).GetNamespace), ctx, name, opts) -} - -// GetNodesByLabels mocks base method. -func (m *MockClientsInterface) GetNodesByLabels(ctx context.Context, matchingLabels map[string]string) (*v10.NodeList, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetNodesByLabels", ctx, matchingLabels) - ret0, _ := ret[0].(*v10.NodeList) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetNodesByLabels indicates an expected call of GetNodesByLabels. -func (mr *MockClientsInterfaceMockRecorder) GetNodesByLabels(ctx, matchingLabels interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNodesByLabels", reflect.TypeOf((*MockClientsInterface)(nil).GetNodesByLabels), ctx, matchingLabels) -} - -// GetPlatform mocks base method. -func (m *MockClientsInterface) GetPlatform() (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPlatform") - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetPlatform indicates an expected call of GetPlatform. -func (mr *MockClientsInterfaceMockRecorder) GetPlatform() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlatform", reflect.TypeOf((*MockClientsInterface)(nil).GetPlatform)) -} - -// GetPodLogs mocks base method. -func (m *MockClientsInterface) GetPodLogs(namespace, podName string, podLogOpts *v10.PodLogOptions) *rest.Request { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPodLogs", namespace, podName, podLogOpts) - ret0, _ := ret[0].(*rest.Request) - return ret0 -} - -// GetPodLogs indicates an expected call of GetPodLogs. -func (mr *MockClientsInterfaceMockRecorder) GetPodLogs(namespace, podName, podLogOpts interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodLogs", reflect.TypeOf((*MockClientsInterface)(nil).GetPodLogs), namespace, podName, podLogOpts) -} - -// GetSecret mocks base method. -func (m *MockClientsInterface) GetSecret(ctx context.Context, namespace, name string, opts v11.GetOptions) (*v10.Secret, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSecret", ctx, namespace, name, opts) - ret0, _ := ret[0].(*v10.Secret) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetSecret indicates an expected call of GetSecret. -func (mr *MockClientsInterfaceMockRecorder) GetSecret(ctx, namespace, name, opts interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecret", reflect.TypeOf((*MockClientsInterface)(nil).GetSecret), ctx, namespace, name, opts) -} - -// HasResource mocks base method. -func (m *MockClientsInterface) HasResource(resource schema.GroupVersionResource) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasResource", resource) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// HasResource indicates an expected call of HasResource. -func (mr *MockClientsInterfaceMockRecorder) HasResource(resource interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasResource", reflect.TypeOf((*MockClientsInterface)(nil).HasResource), resource) -} - -// Invalidate mocks base method. -func (m *MockClientsInterface) Invalidate() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Invalidate") -} - -// Invalidate indicates an expected call of Invalidate. -func (mr *MockClientsInterfaceMockRecorder) Invalidate() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invalidate", reflect.TypeOf((*MockClientsInterface)(nil).Invalidate)) -} - -// List mocks base method. -func (m *MockClientsInterface) List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, obj} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "List", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// List indicates an expected call of List. -func (mr *MockClientsInterfaceMockRecorder) List(ctx, obj interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, obj}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClientsInterface)(nil).List), varargs...) -} - -// ServerGroups mocks base method. -func (m *MockClientsInterface) ServerGroups() (*v11.APIGroupList, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ServerGroups") - ret0, _ := ret[0].(*v11.APIGroupList) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ServerGroups indicates an expected call of ServerGroups. -func (mr *MockClientsInterfaceMockRecorder) ServerGroups() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerGroups", reflect.TypeOf((*MockClientsInterface)(nil).ServerGroups)) -} - -// StatusUpdate mocks base method. -func (m *MockClientsInterface) StatusUpdate(ctx context.Context, obj client.Object) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StatusUpdate", ctx, obj) - ret0, _ := ret[0].(error) - return ret0 -} - -// StatusUpdate indicates an expected call of StatusUpdate. -func (mr *MockClientsInterfaceMockRecorder) StatusUpdate(ctx, obj interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatusUpdate", reflect.TypeOf((*MockClientsInterface)(nil).StatusUpdate), ctx, obj) -} - -// Update mocks base method. -func (m *MockClientsInterface) Update(ctx context.Context, obj client.Object) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Update", ctx, obj) - ret0, _ := ret[0].(error) - return ret0 -} - -// Update indicates an expected call of Update. -func (mr *MockClientsInterfaceMockRecorder) Update(ctx, obj interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockClientsInterface)(nil).Update), ctx, obj) -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/filter/filter.go b/deploy/k8s-operator/kube-trailblazer/pkg/filter/filter.go deleted file mode 100644 index 8f43519fa..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/filter/filter.go +++ /dev/null @@ -1,151 +0,0 @@ -package filter - -import ( - "github.com/nvidia/kube-trailblazer/api/v1alpha1" - operatorv1 "github.com/openshift/api/operator/v1" - "golang.design/x/lockfree" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/predicate" -) - -const ( - Kind = "HelmPipeline" - OwnedLabel = "app.trailblazer.nvidia.com/owned-by" -) - -var ( - WorkStack = make(map[string]*lockfree.Stack) -) - -type Filter interface { - GetPredicates() predicate.Predicate - GetMode() string -} - -func NewFilter() Filter { - WorkStack["DELETE"] = lockfree.NewStack() - return &filter{ - //log: log.WithName("filter"), - //lifecycle: lifecycle, - //storage: storage, - //kernelData: kernelData, - } -} - -type filter struct { - mode string -} - -func (f *filter) GetMode() string { - return f.mode -} - -func (f *filter) isTrailblazerUnmanaged(obj client.Object) bool { - tb, ok := obj.(*v1alpha1.HelmPipeline) - if !ok { - return false - } - return tb.Spec.ManagementState == operatorv1.Unmanaged -} - -func (f *filter) isHelmPipelineObject(obj client.Object) bool { - - _, ok := obj.(*v1alpha1.HelmPipeline) - return ok -} - -func (f *filter) isOwned(obj client.Object) bool { - - for _, owner := range obj.GetOwnerReferences() { - if owner.Kind == Kind { - return true - } - } - - var labels map[string]string - - if labels = obj.GetLabels(); labels != nil { - if _, found := labels[OwnedLabel]; found { - return true - } - } - return false -} - -func (f *filter) selectOnlyOwnedObjects(obj client.Object) bool { - - if f.isHelmPipelineObject(obj) { - if f.isTrailblazerUnmanaged(obj) { - return false - } - klog.Infof("%s - isHelmPipeline - %s -- %s:%s", f.mode, obj.GetNamespace(), obj.GetObjectKind(), obj.GetName()) - if f.mode == "DELETE" { - WorkStack[f.mode].Push(obj) - } - return true - } - - if f.isOwned(obj) { - klog.Infof("%s - isOwned - %s -- %s:%s", f.mode, obj.GetNamespace(), obj.GetObjectKind(), obj.GetName()) - return true - } - return false -} - -func (f *filter) GetPredicates() predicate.Predicate { - return predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { - - f.mode = "CREATE" - return f.selectOnlyOwnedObjects(e.Object) - }, - - UpdateFunc: func(e event.UpdateEvent) bool { - // Ignore updates if the resourceVersion does not change - // resourceVersion is updated when the object is modified - - /* UPDATING THE STATUS WILL INCREASE THE RESOURCEVERSION DISABLING - * BUT KEEPING FOR REFERENCE - if e.MetaOld.GetResourceVersion() == e.MetaNew.GetResourceVersion() { - return false - }*/ - f.mode = "UPDATE" - - ownedObject := f.selectOnlyOwnedObjects(e.ObjectNew) - if !ownedObject { - return false - } - - // Ignore updates to CR status in which case metadata.Generation does not change - if e.ObjectOld.GetGeneration() == e.ObjectNew.GetGeneration() { - klog.Infof("UPDATE Generation Equal %s ", e.ObjectNew.GetName()) - //return false - } - // Some objects will increase generation on update ... - if e.ObjectOld.GetResourceVersion() == e.ObjectNew.GetResourceVersion() { - klog.Infof("UPDATE ResourceVersion Equal %s", e.ObjectNew.GetName()) - //return false - } - - // If a trailblazer dependency is updated we - // want to reconcile it, handle the update event - return f.selectOnlyOwnedObjects(e.ObjectNew) - }, - DeleteFunc: func(e event.DeleteEvent) bool { - - f.mode = "DELETE" - // If an owned object is deleted we - // want to recreate it so handle the delete event - return f.selectOnlyOwnedObjects(e.Object) - }, - GenericFunc: func(e event.GenericEvent) bool { - - f.mode = "GENERIC" - // If a owned object is modified we - // want to reconcile it, handle the generic event - return f.selectOnlyOwnedObjects(e.Object) - }, - } -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/filter/filter_test.go b/deploy/k8s-operator/kube-trailblazer/pkg/filter/filter_test.go deleted file mode 100644 index 7d2736816..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/filter/filter_test.go +++ /dev/null @@ -1,476 +0,0 @@ -package filter - -import ( - "context" - "testing" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/onsi/gomega/types" - appsv1 "k8s.io/api/apps/v1" - "sigs.k8s.io/controller-runtime/pkg/event" - - "github.com/openshift-psap/special-resource-operator/api/v1beta1" - "github.com/openshift-psap/special-resource-operator/pkg/kernel" - "github.com/openshift-psap/special-resource-operator/pkg/lifecycle" - "github.com/openshift-psap/special-resource-operator/pkg/storage" - operatorv1 "github.com/openshift/api/operator/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - ctrl *gomock.Controller - mockLifecycle *lifecycle.MockLifecycle - mockStorage *storage.MockStorage - mockKernel *kernel.MockKernelData - f filter -) - -func TestFilter(t *testing.T) { - RegisterFailHandler(Fail) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockLifecycle = lifecycle.NewMockLifecycle(ctrl) - mockStorage = storage.NewMockStorage(ctrl) - mockKernel = kernel.NewMockKernelData(ctrl) - f = filter{ - //log: zap.New(zap.WriteTo(ioutil.Discard)), - //lifecycle: mockLifecycle, - //storage: mockStorage, - //kernelData: mockKernel, - } - }) - - AfterEach(func() { - ctrl.Finish() - }) - - RunSpecs(t, "Filter Suite") -} - -var _ = Describe("IsTrailblazer", func() { - DescribeTable( - "should return the correct value", - func(obj client.Object, m types.GomegaMatcher) { - Expect(f.isHelmPipelineObject(obj)).To(m) - }, - Entry( - Kind, - &v1beta1.SpecialResource{ - TypeMeta: metav1.TypeMeta{Kind: Kind}, - }, - BeTrue(), - ), - Entry( - "Pod owned by SRO", - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{OwnedLabel: "true"}, - }, - }, - BeFalse(), - ), - Entry( - "valid selflink", - func() *unstructured.Unstructured { - uo := &unstructured.Unstructured{} - uo.SetSelfLink("/apis/sro.openshift.io/v1") - - return uo - }(), - BeTrue(), - ), - Entry( - "selflink in Label", - func() *unstructured.Unstructured { - uo := &unstructured.Unstructured{} - uo.SetLabels(map[string]string{"some-label": "/apis/sro.openshift.io/v1"}) - - return uo - }(), - BeTrue(), - ), - Entry( - "no selflink", - &unstructured.Unstructured{}, - BeFalse(), - ), - ) -}) - -var _ = Describe("Owned", func() { - DescribeTable( - "should return the expected value", - func(obj client.Object, m types.GomegaMatcher) { - Expect(f.isOwned(obj)).To(m) - }, - Entry( - "via ownerReferences", - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - }, - }, - BeTrue(), - ), - Entry( - "via labels", - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{OwnedLabel: "whatever"}, - }, - }, - BeTrue(), - ), - Entry( - "not owned", - &corev1.Pod{}, - BeFalse(), - ), - ) -}) - -var _ = Describe("Predicate", func() { - Context("CreateFunc", func() { - DescribeTable( - "should work as expected", - func(obj client.Object, m types.GomegaMatcher) { - ret := f.GetPredicates().Create(event.CreateEvent{Object: obj}) - - Expect(ret).To(m) - Expect(f.GetMode()).To(Equal("CREATE")) - }, - Entry( - "special resource", - &v1beta1.SpecialResource{}, - BeTrue(), - ), - Entry( - "owned", - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - }, - }, - BeTrue(), - ), - Entry( - "random pod", - &corev1.Pod{}, - BeFalse(), - ), - Entry( - "unmanaged special resource", - &v1beta1.SpecialResource{ - TypeMeta: metav1.TypeMeta{Kind: Kind}, - Spec: v1beta1.SpecialResourceSpec{ - ManagementState: operatorv1.Unmanaged, - }, - }, - BeFalse(), - ), - ) - }) - - Context("UpdateFunc", func() { - DescribeTable( - "should work as expected", - func(mockSetup func(), old client.Object, new client.Object, m types.GomegaMatcher) { - mockSetup() - - ret := f.GetPredicates().Update(event.UpdateEvent{ - ObjectOld: old, - ObjectNew: new, - }) - - Expect(ret).To(m) - Expect(f.GetMode()).To(Equal("UPDATE")) - }, - Entry( - "No change to object's Generation or ResourceVersion", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(false) - }, - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - BeFalse(), - ), - Entry( - "Object's Generation changed, no change to ResourceVersion", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(false) - }, - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 2, - ResourceVersion: "dummy1", - }, - }, - BeFalse(), - ), - Entry( - "Object has changed but is not owned by SRO", - func() {}, - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - ResourceVersion: "dummy2", - }, - }, - BeFalse(), - ), - Entry( - "Object has changed and it's a SRO owned DaemonSet", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(true) - mockLifecycle.EXPECT().UpdateDaemonSetPods(context.TODO(), gomock.Any()) - }, - &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 2, - ResourceVersion: "dummy2", - }, - }, - BeTrue(), - ), - Entry( - "Object is a SRO owned & kernel affine DaemonSet, but did not change", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(true) - }, - &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Annotations: map[string]string{ - "specialresource.openshift.io/kernel-affine": "true", - }, - Generation: 0, - ResourceVersion: "dummy", - }, - }, - &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Annotations: map[string]string{ - "specialresource.openshift.io/kernel-affine": "true", - }, - Generation: 0, - ResourceVersion: "dummy", - }, - }, - BeFalse(), - ), - Entry( - "Object is a SRO owned & kernel affine DaemonSet", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(true) - mockLifecycle.EXPECT().UpdateDaemonSetPods(context.TODO(), gomock.Any()) - }, - &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Annotations: map[string]string{ - "specialresource.openshift.io/kernel-affine": "true", - }, - Generation: 0, - ResourceVersion: "dummy", - }, - }, - &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Annotations: map[string]string{ - "specialresource.openshift.io/kernel-affine": "true", - }, - Generation: 1, - ResourceVersion: "dummy", - }, - }, - BeTrue(), - ), - Entry( - "Object is a SpecialResource with both Generation and ResourceVersion changed", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(false) - }, - &v1beta1.SpecialResource{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - &v1beta1.SpecialResource{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 2, - ResourceVersion: "dummy2", - }, - }, - BeTrue(), - ), - Entry( - "Object is a SpecialResource with both Generation and ResourceVersion changed but unmanaged state", - func() { - mockKernel.EXPECT().IsObjectAffine(gomock.Any()).Return(false) - }, - &v1beta1.SpecialResource{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 1, - ResourceVersion: "dummy1", - }, - }, - &v1beta1.SpecialResource{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - Generation: 2, - ResourceVersion: "dummy2", - }, - Spec: v1beta1.SpecialResourceSpec{ - ManagementState: operatorv1.Unmanaged, - }, - }, - BeFalse(), - ), - ) - }) - - Context("DeleteFunc", func() { - DescribeTable( - "should work as expected", - func(obj client.Object, m types.GomegaMatcher) { - ret := f.GetPredicates().Delete(event.DeleteEvent{Object: obj}) - - Expect(ret).To(m) - Expect(f.GetMode()).To(Equal("DELETE")) - }, - Entry( - "special resource", - &v1beta1.SpecialResource{}, - BeTrue(), - ), - // TODO(qbarrand) testing this function requires injecting a fake pkg/storage - //Entry("owned", ...), - Entry( - "random pod", - &corev1.Pod{}, - BeFalse(), - ), - ) - }) - - Context("GenericFunc", func() { - DescribeTable( - "should return the correct value", - func(obj client.Object, m types.GomegaMatcher) { - ret := f.GetPredicates().Generic(event.GenericEvent{Object: obj}) - - Expect(ret).To(m) - Expect(f.GetMode()).To(Equal("GENERIC")) - }, - Entry( - "special resource", - &v1beta1.SpecialResource{}, - BeTrue(), - ), - Entry( - "owned", - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - {Kind: Kind}, - }, - }, - }, - BeTrue(), - ), - Entry( - "random pod", - &corev1.Pod{}, - BeFalse(), - ), - Entry( - "unmanaged special resource", - &v1beta1.SpecialResource{ - TypeMeta: metav1.TypeMeta{Kind: Kind}, - Spec: v1beta1.SpecialResourceSpec{ - ManagementState: operatorv1.Unmanaged, - }, - }, - BeFalse(), - ), - ) - }) -}) diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/LICENSE b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/README.md b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/README.md deleted file mode 100644 index e86bd4b74..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/README.md +++ /dev/null @@ -1 +0,0 @@ -# helmer \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/chart.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/chart.go deleted file mode 100644 index 1502167ec..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/chart.go +++ /dev/null @@ -1,72 +0,0 @@ -package helmer - -import helmclient "github.com/mittwald/go-helm-client" - -func (in *chartSpec) DeepCopyInto(out *helmclient.ChartSpec) { - - // copy all chartSpec fields from out to in - out.ReleaseName = in.ReleaseName - out.ChartName = in.ChartName - out.Namespace = in.Namespace - out.ValuesYaml = in.ValuesYaml - out.ValuesOptions = in.ValuesOptions - out.Version = in.Version - out.CreateNamespace = in.CreateNamespace - out.DisableHooks = in.DisableHooks - out.Replace = in.Replace - out.Wait = in.Wait - out.WaitForJobs = in.WaitForJobs - out.DependencyUpdate = in.DependencyUpdate - out.Timeout = in.Timeout - out.GenerateName = in.GenerateName - out.NameTemplate = in.NameTemplate - out.Atomic = in.Atomic - out.SkipCRDs = in.SkipCRDs - out.UpgradeCRDs = in.UpgradeCRDs - out.SubNotes = in.SubNotes - out.Force = in.Force - out.ResetValues = in.ResetValues - out.ReuseValues = in.ReuseValues - out.Recreate = in.Recreate - out.MaxHistory = in.MaxHistory - out.CleanupOnFail = in.CleanupOnFail - out.DryRun = in.DryRun - out.Description = in.Description - out.KeepHistory = in.KeepHistory -} - -func (in *chartSpec) DeepCopy() *helmclient.ChartSpec { - - var out helmclient.ChartSpec - // copy all chartSpec fields from out to in - out.ReleaseName = in.ReleaseName - out.ChartName = in.ChartName - out.Namespace = in.Namespace - out.ValuesYaml = in.ValuesYaml - out.ValuesOptions = in.ValuesOptions - out.Version = in.Version - out.CreateNamespace = in.CreateNamespace - out.DisableHooks = in.DisableHooks - out.Replace = in.Replace - out.Wait = in.Wait - out.WaitForJobs = in.WaitForJobs - out.DependencyUpdate = in.DependencyUpdate - out.Timeout = in.Timeout - out.GenerateName = in.GenerateName - out.NameTemplate = in.NameTemplate - out.Atomic = in.Atomic - out.SkipCRDs = in.SkipCRDs - out.UpgradeCRDs = in.UpgradeCRDs - out.SubNotes = in.SubNotes - out.Force = in.Force - out.ResetValues = in.ResetValues - out.ReuseValues = in.ReuseValues - out.Recreate = in.Recreate - out.MaxHistory = in.MaxHistory - out.CleanupOnFail = in.CleanupOnFail - out.DryRun = in.DryRun - out.Description = in.Description - out.KeepHistory = in.KeepHistory - - return &out -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/Makefile b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/Makefile deleted file mode 100644 index 4d9772c1a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -helm: - ../hack/helmer.sh - -GRAPH ?= ${HOME}/github.com/zvonkok/helmer/graphs/helmer-nfd.yaml - -run: helm - go mod tidy - go mod vendor - cp patches/root.go vendor/helm.sh/helm/v3/pkg/chart/. - go run . -g $(GRAPH) - - diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/controller.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/controller.go deleted file mode 100644 index 8951956c1..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/controller.go +++ /dev/null @@ -1,133 +0,0 @@ -package main - -import ( - "flag" - "log" - "os" - - cli "github.com/urfave/cli/v2" - - "github.com/nvidia/kube-trailblazer/pkg/helmer" - klog "k8s.io/klog/v2" -) - -func init() { - flags := flag.FlagSet{ - Usage: func() { - }, - } - // Default is logtostderr - klog.InitFlags(&flags) -} - -func main() { - - var err error - var graphs cli.StringSlice - var kubeConfig string - - app := &cli.App{ - Name: "helmer", - Usage: "reconcile a helm graph", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "kubeConfig", - Aliases: []string{"k"}, - DefaultText: "${HOME}/.kube/config", - Value: "${HOME}/.kube/config", - Destination: &kubeConfig, - }, - &cli.StringSliceFlag{ - Name: "graphs", - Aliases: []string{"g"}, - Required: true, - DefaultText: "None", - Destination: &graphs, - }, - }, - Action: func(c *cli.Context) error { - return nil - }, - } - - app.Run(os.Args) - if err != nil { - log.Fatal(err) - } - - os.Setenv("HELMER_DEBUG", "1") - - for _, fromFile := range graphs.Value() { - - var orchard helmer.Pipeline - // We're providing Helmer a Graph as the interface what to create - // In an operator we would have a go struct but for testing we can - // also load a Graph from file. - orchard, err = helmer.LoadPipeline(fromFile) - if err != nil { - panic(err) - } - - // RECONCILE LOOP - for _, arbor := range orchard { - - // For each chart we create an Helmer instance with its own settings - // this makes it easier to decouple each chart for processing and clients - // that do not interfere with each other. - h, err := helmer.NewWithPackage(&arbor) - if err != nil { - panic(err) - } - - err = h.GetClientsWithKubeConf("", "default") - if err != nil { - panic(err) - } - - err = h.AddOrUpdateRepo() - if err != nil { - panic(err) - } - - err = h.Lint() - if err != nil { - panic(err) - } - - // klog.Info("TEMPLATE") - // err = h.Template() - // if err != nil { - // panic(err) - // } - - reconcile(h) - } - - } - return -} - -func reconcile(h *helmer.Helmer) { - - for { - err := h.InstallOrUpgradePackage() - if err != nil { - klog.Info(err) - } - if err == nil { - break - } - } -} - -/* -func OpenShiftInstallOrder() { - // Mutates helm package exported variables - idx := utils.StringSliceFind(releaseutil.InstallOrder, "Service") - releaseutil.InstallOrder = utils.StringSliceInsert(releaseutil.InstallOrder, idx, "BuildConfig") - releaseutil.InstallOrder = utils.StringSliceInsert(releaseutil.InstallOrder, idx, "ImageStream") - releaseutil.InstallOrder = utils.StringSliceInsert(releaseutil.InstallOrder, idx, "SecurityContextConstraints") - releaseutil.InstallOrder = utils.StringSliceInsert(releaseutil.InstallOrder, idx, "Issuer") - releaseutil.InstallOrder = utils.StringSliceInsert(releaseutil.InstallOrder, idx, "Certificates") -} -*/ diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/patches/root.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/patches/root.go deleted file mode 100644 index fa1eb832a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/patches/root.go +++ /dev/null @@ -1,8 +0,0 @@ -package chart - -// NotRoot not root -func (ch *Chart) NotRoot() { - ch.parent = nil - ch.dependencies = nil - ch.Metadata.Dependencies = nil -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/test.yaml b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/test.yaml deleted file mode 100644 index 7c6f21f26..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/controller/test.yaml +++ /dev/null @@ -1,34 +0,0 @@ - - - repoEntry: - name: "zvonkok" - url: "https://zvonkok.github.io/helm-charts/" - chartSpec: - release: "flannel" - chart: "zvonkok/flannel" - namespace: "flannel" - version: "v0.23.0" - - - repoEntry: - name: "nfd" - url: "https://kubernetes-sigs.github.io/node-feature-discovery/charts" - chartSpec: - release: "node-feature-discovery" - chart: "nfd/node-feature-discovery" - namespace: "node-feature-discovery" - version: "0.14.3" - chartValues: - kernelVersion: "{{ tpl .Values.runtime.kernelVersiosn }}" # {{ tpl .Values.chartValues.kernelVersion . }} - - - repoEntry: - name: "nvidia" - url: "https://helm.ngc.nvidia.com/nvidia" - chartSpec: - release: "gpu-operator" - chart: "nvidia/gpu-operator" - namespace: "gpu-operator" - version: "v23.9.0" - chartValues: - nfd: - enabled: false - mig: - strategy: "single" diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-kubevirt.yaml b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-kubevirt.yaml deleted file mode 100644 index 6715eed13..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-kubevirt.yaml +++ /dev/null @@ -1,41 +0,0 @@ -repoEntry: - name: "nvidia" - url: "file:///home/zvonkok/helm-charts/nvidia" - username: "" - password: "" - certFile: "" - keyFile: "" - caFile: "" - insecure_skip_tls_verify: false - pass_credentials_all: false - -chartSpec: - release: "nvidia-kubevirt" - chart: "nvidia/kata-device-plugin" - namespace: "nvidia" - valuesYaml: "" - version: "1.1.1" - createNamespace: true - disableHooks: false - replace: true - wait: true - waitForJobs: true - dependencyUpdate: false - timeout: 10000000000 - generateName: true - NameTemplate: "" - atomic: false - skipCRDs: false - upgradeCRDs: true - subNotes: false - force: false - resetValues: false - reuseValues: false - recreate: false - maxHistory: 0 - cleanupOnFail: false - dryRun: false - # postRenderer: "setN" - -chartValues: - kernelVersion: "{{ tpl .Values.runtime.kernelVersion }}" # {{ tpl .Values.chartValues.kernelVersion . }} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nfd.yaml b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nfd.yaml deleted file mode 100644 index 96eded613..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nfd.yaml +++ /dev/null @@ -1,10 +0,0 @@ -- repoEntry: - name: "nfd" - url: "https://kubernetes-sigs.github.io/node-feature-discovery/charts" - chartSpec: - release: "node-feature-discovery" - chart: "nfd/node-feature-discovery" - namespace: "node-feature-discovery" - version: "0.14.3" - chartValues: - kernelVersion: "{{ tpl .Values.runtime.kernelVersion }}" # {{ tpl .Values.chartValues.kernelVersion . }} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nvidia-kata.yaml b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nvidia-kata.yaml deleted file mode 100644 index f96b8f820..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nvidia-kata.yaml +++ /dev/null @@ -1,41 +0,0 @@ -repoEntry: - name: "nvidia" - url: "file:///home/zvonkok/helm-charts/nvidia" - username: "" - password: "" - certFile: "" - keyFile: "" - caFile: "" - insecure_skip_tls_verify: false - pass_credentials_all: false - -chartSpec: - release: "nvidia-kata" - chart: "nvidia/nvidia-kata" - namespace: "nvidia" - valuesYaml: "" - version: "0.3.0" - createNamespace: true - disableHooks: false - replace: true - wait: true - waitForJobs: true - dependencyUpdate: false - timeout: 10000000000 - generateName: true - NameTemplate: "" - atomic: false - skipCRDs: false - upgradeCRDs: true - subNotes: false - force: false - resetValues: false - reuseValues: false - recreate: false - maxHistory: 0 - cleanupOnFail: false - dryRun: false - # postRenderer: "setN" - -chartValues: - kernelVersion: "{{ tpl .Values.runtime.kernelVersion }}" # {{ tpl .Values.chartValues.kernelVersion . }} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nvidia-vgpu.yaml b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nvidia-vgpu.yaml deleted file mode 100644 index 67e0c6117..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/graphs/helmer-nvidia-vgpu.yaml +++ /dev/null @@ -1,41 +0,0 @@ -repoEntry: - name: "nvidia" - url: "file:///home/zvonkok/helm-charts/nvidia" - username: "" - password: "" - certFile: "" - keyFile: "" - caFile: "" - insecure_skip_tls_verify: false - pass_credentials_all: false - -chartSpec: - release: "nvidia-vgpu" - chart: "nvidia/nvidia-vgpu" - namespace: "nvidia" - valuesYaml: "" - version: "0.2.0" - createNamespace: true - disableHooks: false - replace: true - wait: true - waitForJobs: true - dependencyUpdate: false - timeout: 10000000000 - generateName: true - NameTemplate: "" - atomic: false - skipCRDs: false - upgradeCRDs: true - subNotes: false - force: false - resetValues: false - reuseValues: false - recreate: false - maxHistory: 0 - cleanupOnFail: false - dryRun: false - # postRenderer: "setN" - -chartValues: - kernelVersion: "{{ tpl .Values.runtime.kernelVersion }}" # {{ tpl .Values.chartValues.kernelVersion . }} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/hack/helmer.sh b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/hack/helmer.sh deleted file mode 100755 index 471e93820..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/hack/helmer.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -HELM_PLUGINS=$(realpath ../plugins) -export HELM_PLUGINS - -HELM_CHARTS_DIR=${HOME}/helm-charts -HELM_REPOS=$(ls -d ${HELM_CHARTS_DIR}/*) -HELM_TMP_DIR=$(mktemp -d) - -function lint { - helm lint --with-subcharts --strict "${CHARTS}" -} - -function package { - helm package "${CHARTS}" --destination "${REPO}" -} - -function repo_index { - helm repo index "${REPO}" --url=file:///${REPO} -} - -function dependency_update { - for CHART in ${CHARTS} - do - helm dependency update "${CHART}" - done -} - -function template { - for CHART in ${CHARTS} - do - MANIFESTS=${HELM_TMP_DIR}/$(basename "${CHART}").yaml - echo "==> Templating ${CHART}" - echo "[INFO] ${MANIFESTS}" - echo "" - helm template --name-template=nvidia "${CHART}" > "${MANIFESTS}" - done -} - - -function kube_linter { - echo "kube-linter" -} - -function helmer_prereq { - ln -sf "${HELM_PLUGINS}" /tmp/.helmplugins -} - -function helmer { - COMMAND=$1 - for REPO in ${HELM_REPOS} - do - CHARTS=$(ls -d "${REPO}"/*/) - ${COMMAND} - done -} - - -helmer_prereq - -#helmer lint -helmer dependency_update -helmer package -helmer repo_index -helmer lint -helmer template -helmer kube_linter - diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/helmer.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/helmer.go deleted file mode 100644 index 5207ae77b..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/helmer.go +++ /dev/null @@ -1,599 +0,0 @@ -package helmer - -import ( - "bytes" - "context" - "encoding/json" - "log" - "os" - "reflect" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - - helmclient "github.com/mittwald/go-helm-client" - "github.com/nvidia/kube-trailblazer/pkg/clients" - "github.com/nvidia/kube-trailblazer/pkg/utils" - "github.com/pkg/errors" - "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/chart" - "helm.sh/helm/v3/pkg/chartutil" - "helm.sh/helm/v3/pkg/release" - "helm.sh/helm/v3/pkg/repo" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" -) - -const ( - FilterKind = "HelmPipeline" - FilterOwnedLabel = "app.trailblazer.nvidia.com/owned-by" -) - -func (h *Helmer) GetClientsWithRestConf(restConf *rest.Config) error { - - var err error - - opt := &helmclient.RestConfClientOptions{ - Options: &helmclient.Options{ - Namespace: h.Package.ChartSpec.Namespace, // Change this to the namespace you wish to install the chart in. - RepositoryCache: "/tmp/.helmcache", - RepositoryConfig: "/tmp/.helmrepo", - Debug: true, - Linting: false, // Change this to false if you don't want linting. - DebugLog: klog.Infof, - }, - RestConfig: restConf, - } - - h.Client, err = helmclient.NewClientFromRestConf(opt) - if err != nil { - return errors.Wrap(err, "\n[GGetClientWithRestConf]\tcannot create client from restConfig") - } - h.KubeClient, err = clients.NewKubeClientsFromRestConf(restConf) - if err != nil { - return errors.Wrapf(err, "\n[GGetClientWithRestConf]\tcannot create kubeClients from restConfig") - } - return nil -} - -// GetClientWithKubeConf create a Helmer with a supplied KubeConf -func (h *Helmer) GetClientsWithKubeConf(path string, kubeContext string) error { - - if path == "" { - homeDir, err := os.UserHomeDir() - if err != nil { - return errors.Wrapf(err, "\n[GetClientWithKubeConf]\tcannot read user home dir") - } - path = homeDir + "/.kube/config" - } - - kubeConfig, err := os.ReadFile(path) - if err != nil { - return errors.Wrapf(err, "\n[GetClientWithKubeConf]\tcannot read kubeConfig from path %s:%v", path, err) - } - - opt := &helmclient.KubeConfClientOptions{ - Options: &helmclient.Options{ - Namespace: h.Package.ChartSpec.Namespace, // Change this to the namespace you wish to install the chart in. - RepositoryCache: "/tmp/.helmcache", - RepositoryConfig: "/tmp/.helmrepo", - Debug: true, - Linting: false, // Change this to false if you don't want linting. - DebugLog: klog.Infof, - }, - KubeContext: kubeContext, - KubeConfig: kubeConfig, - } - - h.Client, err = helmclient.NewClientFromKubeConf(opt) - if err != nil { - return errors.Wrap(err, "\n[GetClientWithKubeConf]\tcannot create client from kubeConfig") - } - - clientCfg, err := clientcmd.NewClientConfigFromBytes(kubeConfig) - if err != nil { - log.Fatal(err) - } - - restConf, err := clientCfg.ClientConfig() - if err != nil { - log.Fatal(err) - } - h.KubeClient, err = clients.NewKubeClientsFromRestConf(restConf) - if err != nil { - return errors.Wrapf(err, "\n[GGetClientWithRestConf]\tcannot create kubeClients from restConfig") - } - return nil -} - -// New creates a simple Helmer object with debugging flag set -func New() (*Helmer, error) { - - h := &Helmer{ - Debug: false, - } - - os.Setenv("HELM_DEBUG", "1") - //os.Setenv("HELM_PLUGINS", "/tmp/.helmplugins") - - if debug := os.Getenv("HELMER_DEBUG"); debug == "1" { - h.Debug = true - } - - h.Options = helmclient.GenericHelmOptions{ - PostRenderer: h, - RollBack: nil, - } - - return h, nil -} - -// NewWithPackage creates a very simple Helmer object -func NewWithPackage(pkg *HelmPackage) (*Helmer, error) { - - h, _ := New() - h.Package = *pkg - - // TODO: Is there a better place to have this logic? BEGIN - hash, err := utils.FNV64a(h.Package.RepoEntry.URL) - if err != nil { - return nil, errors.Wrapf(err, "[NewWithPackage] cannot create hash for repo ") - } - - if h.Package.RepoEntry.Name == "" { - h.Package.RepoEntry.Name = hash - } - - if h.Package.ChartSpec.Namespace == "" { - h.Package.ChartSpec.Namespace = h.Package.ChartSpec.ChartName - h.Package.ChartSpec.CreateNamespace = true - } - - if h.Package.ChartSpec.ReleaseName == "" { - h.Package.ChartSpec.ReleaseName = h.Package.ChartSpec.ChartName + "-" + hash - } - // Replace the chart name with the full chart name - h.Package.ChartSpec.ChartName = h.Package.RepoEntry.Name + "/" + h.Package.ChartSpec.ChartName - // TODO: Is there a better place to have this logic? END - - // This is needed for housekeeping between rootChart and childChart - h.Package.ReleaseName = h.Package.ChartSpec.ReleaseName - - return h, nil -} - -// LoadPipeline loads an Pipeline from various sources -func LoadPipeline(object interface{}) (Pipeline, error) { - - var err error - var pipeline Pipeline - switch t := object.(type) { - case string: - - klog.Info("Pipeline:", object) - if pipeline, err = LoadPipelineFromFile(t); err != nil { - return nil, errors.Wrapf(err, "\n[LoadPipeline]\tfailed loading Package from file: %s", t) - } - return pipeline, nil - - case map[string]interface{}: - - klog.Info("Pipeline:", object) - if pipeline, err = LoadPipelineFromObject(t); err != nil { - return nil, errors.Wrapf(err, "\n[LoadPipeline]\tfailed loading Package from map: %v", t) - } - - return pipeline, nil - - default: - return nil, errors.New("\n[Load]\tcannot construct Package from type: " + reflect.TypeOf(object).String()) - } -} - -// LoadPipelineFromFile reads an Pipeline object from provided YANL file -func LoadPipelineFromFile(file string) (Pipeline, error) { - - var orhcard Pipeline - - yamlText, err := os.ReadFile(file) - if err != nil { - return nil, errors.Wrapf(err, "\n[LoadPackageFromFile]\tcannot read %s from path %s:%v", yamlText, file, err) - } - - jsonText, err := yaml.YAMLToJSON(yamlText) - if err != nil { - return nil, errors.Wrapf(err, "\n[LoadPackageFromFile]\tfailed on %s", yamlText) - } - dec := json.NewDecoder(bytes.NewReader(jsonText)) - dec.DisallowUnknownFields() - - if err := dec.Decode(&orhcard); err != nil { - return nil, errors.Wrapf(err, "\n[LoadPackageFromFile]\tfailed on %s", jsonText) - } - return UpdatePipelineWithDefaultChartSpec(orhcard), err -} - -// LoadPipelineFromObject loads an Pipeline from a CR or any other YAML like object -func LoadPipelineFromObject(object map[string]interface{}) (Pipeline, error) { - - var pipeline Pipeline - - UpdatePipelineWithDefaultChartSpec(pipeline) - return pipeline, nil -} - -// GetChart loads the chart from the repo -func (h *Helmer) GetChart(chartSpec *helmclient.ChartSpec) (*chart.Chart, error) { - - chart, _, err := h.Client.GetChart(chartSpec.ChartName, &action.ChartPathOptions{}) - return chart, err - -} - -// InstallOrUpgradePackage implements HelmHelper -func (h *Helmer) InstallOrUpgradePackage() error { - - // The graph chart values can override chart.Values - rootValues := h.Package.ChartValues - - chartSpec := h.Package.ChartSpec.DeepCopy() - rootChart, err := h.GetChart(chartSpec) - if err != nil { - return errors.Wrapf(err, "\n[InstallOrUpgradePackage]\tcannot get Chart from Package %s", h.Package.ChartSpec.ReleaseName) - } - err = h.install(rootChart, &rootValues) - if err != nil { - return errors.Wrapf(err, "\n[InstallOrUpgradePackage]\tcannot install Chart from Package %s", h.Package.ChartSpec.ReleaseName) - } - - return nil -} - -func checkKubeAPIErrors(err error, msg string) error { - if apierrors.IsNotFound(err) { - return errors.Wrapf(err, "[checkKubeAPIErrors]\t%s not found", msg) - - } - if apierrors.IsForbidden(err) { - return errors.Wrapf(err, "[checkKubeAPIErrors]\tforbidden, check Role, ClusterRole and Bindings for operator") - } - - if err != nil { - return errors.Wrapf(err, "[checkKubeAPIErrors]\tunexpected error") - } - return nil -} - -func (h *Helmer) setReleaseOwnerReference(chartRelease *release.Release) error { - - matchingLabels := map[string]string{ - "owner": "helm", - "name": chartRelease.Name, - "status": "deployed", - } - - opts := []client.ListOption{ - client.InNamespace(chartRelease.Namespace), - client.MatchingLabels(matchingLabels), - } - - secrets := unstructured.UnstructuredList{} - secrets.SetAPIVersion("v1") - secrets.SetKind("SecretList") - - err := h.KubeClient.List(context.TODO(), &secrets, opts...) - if checkKubeAPIErrors(err, "SecretList"); err != nil { - return errors.Wrapf(err, "[setReleaseOwnerReference]\tcannot list secrets for chartRelease: ", chartRelease.Name) - } - - for _, secret := range secrets.Items { - labels := secret.GetLabels() - labels[FilterOwnedLabel] = FilterKind - - secret.SetLabels(labels) - klog.Infof("[setReleaseOwnerReference]\tupdating release %s:%s", secret.GetNamespace(), secret.GetName()) - err := h.KubeClient.Update(context.Background(), &secret) - if checkKubeAPIErrors(err, "Secret"); err != nil { - return errors.Wrapf(err, "[setReleaseOwnerReference]\tcannot update secret for chartRelease: ", chartRelease.Name) - } - } - - return nil -} - -func (h *Helmer) install(rootChart *chart.Chart, rootValues *chartutil.Values) error { - - var err error - // TODO: Sharing Templates with Subcharts - // Parent charts and subcharts can share templates. - // Any defined block in any chart is available to other charts. - //for _, childChart := range rootChart { - // id := childChart.ChartFullPath() - //} - - // rootValues will hold the value overrides for the child chart - *rootValues, err = chartutil.CoalesceValues(rootChart, rootValues.AsMap()) - if err != nil { - return errors.Wrapf(err, "\n[Install]\tcoalesce values failed %v", rootChart.Name()) - } - - err = chartutil.ProcessDependencies(rootChart, *rootValues) - if err != nil { - return errors.Wrapf(err, "\n[Install]\tprocess dependencies failed for %v", rootChart.Name()) - } - - // We need the initial releaseName since we're updating each child chart - // with a new releaseName, this way we are not concat relase + child0 + child1 - h.installDependencies(rootChart.Dependencies(), rootValues) - - // Reset the releasename if we are the original root chart - if rootChart.IsRoot() { - h.Package.ChartSpec.ReleaseName = h.Package.ReleaseName - } - // Need to reset the root flag, helm aggregates all Values and templates - // if it is a root chart it will only populate the child values with - // the root .Value.childChart not the actual child values - rootChart.NotRoot() - - vals, err := rootValues.YAML() - if err != nil { - return errors.Wrapf(err, "\n[Install]\tcannot convert rootValues to YAML") - } - - h.Package.ChartSpec.ValuesYaml = vals - - chartSpec := h.Package.ChartSpec.DeepCopy() - chartRelease, err := h.Client.InstallOrUpgradeChart(context.TODO(), chartSpec, &h.Options) - if err != nil { - return errors.Wrapf(err, "\n[Install]\tchart failed with %v", rootChart.Name()) - } - - err = h.setReleaseOwnerReference(chartRelease) - if err != nil { - return errors.Wrapf(err, "\n[Install]\tcannot setReleaseOwnerReference for charRelease %s", chartRelease.Name) - } - - return nil -} - -func (h *Helmer) installDependencies(rootChart []*chart.Chart, rootValues *chartutil.Values) error { - - childValues := chartutil.Values{} - - for _, childChart := range rootChart { - - // Overriding Values from a Parent Values - // The value at the top level can override the - // value of the subchart. - if rootOverride, err := rootValues.Table(childChart.Name()); err == nil { - childValues = chartutil.CoalesceTables(childValues, rootOverride) - } - - // Global Chart Values - // Global values are values that can be accessed from any - // chart or subchart by exactly the same name. - if rootGlobal, err := rootValues.Table("global"); err == nil { - childGlobal, err := childValues.Table("global") - if err != nil { - return errors.Wrap(err, "\n[installDependencies]\tcannot extract global from childValues") - } - childValues["global"] = chartutil.CoalesceTables(childGlobal, rootGlobal) - } - - h.installDependency(childChart, &childValues) - } - return nil -} - -func (h *Helmer) updateChildPackage(childChart *chart.Chart) { - h.Package.ChartSpec.ReleaseName = h.Package.ReleaseName + "-" + childChart.Name() - h.Package.ChartSpec.ChartName = h.Package.RepoEntry.Name + "/" + childChart.Name() - h.Package.ChartSpec.Version = childChart.Metadata.Version -} - -func (h *Helmer) installDependency(childChart *chart.Chart, childValues *chartutil.Values) error { - - // For each chart we create an Helmer instance with its own settings - // this makes it easier to decouple each chart for processing and clients - // that do not interfere with each other. - - // Copy root definitions and apply to child charts, we may think of - // own graph definitions for child charts - h.updateChildPackage(childChart) - - klog.Info(h.Package.ChartSpec) - - c, err := NewWithPackage(&h.Package) - if err != nil { - return errors.Wrapf(err, "\n[installDependency]\tcannot create new Helmer with Package %s", h.Package.ChartSpec.ReleaseName) - } - - // TODO: add generic client which can handle "all" situations - err = c.GetClientsWithKubeConf("", "default") - if err != nil { - return errors.Wrapf(err, "\n[installDependency]\tcannot get client with kubeConf") - } - - klog.Info("[InstallChildChart]: ", childChart.Name()) - - err = c.install(childChart, childValues) - if err != nil { - return errors.Wrapf(err, "\n[installDependency]\tcannot install chart: %s", childChart.Name()) - } - return nil -} - -// Upgrade implements HelmHelper -func (h *Helmer) Upgrade() error { - panic("unimplemented") -} - -// Lint implement HelmHelper -func (h *Helmer) Lint() error { - chartSpec := h.Package.ChartSpec.DeepCopy() - if err := h.Client.LintChart(chartSpec); err != nil { - return errors.Wrap(err, "[Lint] failed linting chart") - } - return nil -} - -// Template implement HelmHelper -func (h *Helmer) Template() error { - var err error - yamls := []byte{} - chartSpec := h.Package.ChartSpec.DeepCopy() - if yamls, err = h.Client.TemplateChart(chartSpec, nil); err != nil { - return errors.Wrap(err, "[Template] templating failed") - } - if h.Debug { - klog.Info(string(yamls)) - } - - return nil -} - -// AddOrUpdateRepo implements HelmHelper -func (h *Helmer) AddOrUpdateRepo() error { - - var repoEntry repo.Entry - - h.Package.RepoEntry.DeepCopyInto(&repoEntry) - if err := h.Client.AddOrUpdateChartRepo(repoEntry); err != nil { - return errors.Wrapf(err, "[AddOrUpdateChartRepo] failed with repo entry %v", h.Package.RepoEntry) - } - - return nil -} - -func (h *Helmer) RunChartTests() (bool, error) { - return h.Client.RunChartTests(h.Package.ChartSpec.ReleaseName) -} - -func ReconcileDelete(pipeline Pipeline, restConf *rest.Config) error { - for _, pkg := range UpdatePipelineWithDefaultChartSpec(pipeline) { - - // For each chart we create an Helmer instance with its own settings - // this makes it easier to decouple each chart for processing and clients - // that do not interfere with each other. - h, err := NewWithPackage(&pkg) - if err != nil { - panic(err) - } - - err = h.GetClientsWithRestConf(restConf) - if err != nil { - panic(err) - } - chartSpec := h.Package.ChartSpec.DeepCopy() - err = h.UninstallRelease(chartSpec) - if err != nil { - return errors.Wrapf(err, "\n[ReconcileDelete]\tcannot uninstall release %s", h.Package.ChartSpec.ReleaseName) - } - } - return nil -} - -func ReconcileCreate(pipeline Pipeline, restConf *rest.Config) ([]*release.Release, error) { - - var releases []*release.Release - - for _, pkg := range UpdatePipelineWithDefaultChartSpec(pipeline) { - // For each chart we create an Helmer instance with its own settings - // this makes it easier to decouple each chart for processing and clients - // that do not interfere with each other. - h, err := NewWithPackage(&pkg) - if err != nil { - panic(err) - } - - err = h.GetClientsWithRestConf(restConf) - if err != nil { - panic(err) - } - err = h.AddOrUpdateRepo() - if err != nil { - return nil, err - } - - err = h.Lint() - if err != nil { - return nil, err - } - err = h.InstallOrUpgradePackage() - if err != nil { - return nil, err - } - ok, err := h.RunChartTests() - if !ok { - klog.Infof("[Reconcile]\tchart tests failed for %s", h.Package.ChartSpec.ReleaseName) - return nil, err - } - if err != nil { - klog.Infof("[Reconcile]\terror executing tests for %s", h.Package.ChartSpec.ReleaseName) - - } - if err == nil { - releases, err = h.ListDeployedReleases() - if err != nil { - return nil, err - } - } - } - return releases, nil -} - -// UpdateGrapshWithDefaultChartSpec updates a HelmPackage with default ChartSpec values -func UpdatePipelineWithDefaultChartSpec(in Pipeline) Pipeline { - var out Pipeline - for _, pkg := range in { - pkg.ChartSpec.CreateNamespace = true - pkg.ChartSpec.DisableHooks = false - pkg.ChartSpec.Replace = true - pkg.ChartSpec.Wait = true - pkg.ChartSpec.WaitForJobs = true - pkg.ChartSpec.DependencyUpdate = false - pkg.ChartSpec.Timeout = 10000000000 - pkg.ChartSpec.GenerateName = false - pkg.ChartSpec.NameTemplate = "" - pkg.ChartSpec.Atomic = false - pkg.ChartSpec.SkipCRDs = false - pkg.ChartSpec.UpgradeCRDs = true - pkg.ChartSpec.SubNotes = false - pkg.ChartSpec.Force = false - pkg.ChartSpec.ResetValues = false - pkg.ChartSpec.ReuseValues = false - pkg.ChartSpec.Recreate = false - // Keep this at one, otherwise we will have a lot of - // incomplete releases because of reconciliation - pkg.ChartSpec.MaxHistory = 0 - pkg.ChartSpec.CleanupOnFail = false - pkg.ChartSpec.DryRun = false - pkg.ChartSpec.Description = "" - pkg.ChartSpec.KeepHistory = false - out = append(out, pkg) - } - return out -} - -func (h *Helmer) UninstallRelease(spec *helmclient.ChartSpec) error { - return h.Client.UninstallRelease(spec) -} -func (h *Helmer) ListDeployedReleases() ([]*release.Release, error) { - - ownedReleases := make([]*release.Release, 0) - - chartReleases, err := h.Client.ListDeployedReleases() - if err != nil { - - } - for _, chartRelease := range chartReleases { - if chartRelease.Labels[FilterOwnedLabel] == FilterKind { - ownedReleases = append(ownedReleases, chartRelease) - } - - } - return ownedReleases, nil -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/interface.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/interface.go deleted file mode 100644 index d11494451..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/interface.go +++ /dev/null @@ -1,23 +0,0 @@ -package helmer - -import ( - helmclient "github.com/mittwald/go-helm-client" - "helm.sh/helm/v3/pkg/chart" - "helm.sh/helm/v3/pkg/release" - "k8s.io/client-go/rest" -) - -// Interface a helm hepler Helper -type Interface interface { - InstallOrUpgradePackage() error - Upgrade() error - Lint() error - Template() error - AddOrUpdateRepo() error - GetClientsWithKubeConf(path string, kubeContext string) error - GetClientsWithRestConf(restConf *rest.Config) error - GetChart(char *helmclient.ChartSpec) (*chart.Chart, error) - RunChartTests() (bool, error) - UninstallRelease(spec *helmclient.ChartSpec) error - ListDeployedReleases() ([]*release.Release, error) -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/package.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/package.go deleted file mode 100644 index 8abae9f4a..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/package.go +++ /dev/null @@ -1,62 +0,0 @@ -package helmer - -import ( - "github.com/mittwald/go-helm-client/values" -) - -// NewHelmPackageWithDefaultChartSpec creates a new HelmPackage with default ChartSpec values -// that trailblazer things may be usefull -func NewHelmPackageWithDefaultChartSpec() *HelmPackage { - pipeline := &HelmPackage{ - RepoEntry: repoEntry{}, - ChartSpec: chartSpec{ - ReleaseName: "", - ChartName: "", - Namespace: "", - ValuesYaml: "", - ValuesOptions: values.Options{}, - Version: "", - CreateNamespace: true, - DisableHooks: false, - Replace: true, - Wait: true, - WaitForJobs: true, - DependencyUpdate: false, - Timeout: 90000000000, - GenerateName: true, - NameTemplate: "", - Atomic: false, - SkipCRDs: false, - UpgradeCRDs: true, - SubNotes: false, - Force: false, - ResetValues: false, - ReuseValues: false, - Recreate: false, - MaxHistory: 1, - CleanupOnFail: false, - DryRun: false, - Description: "", - KeepHistory: false, - }, - ChartValues: make(map[string]interface{}), - ReleaseName: "", - } - return pipeline -} - -func (in *HelmPackage) DeepCopyInto(out *HelmPackage) { - *out = *in - out.RepoEntry = in.RepoEntry - out.ChartSpec = in.ChartSpec - out.ChartValues = in.ChartValues -} - -func (in *HelmPackage) DeepCopy() *HelmPackage { - if in == nil { - return nil - } - out := new(HelmPackage) - in.DeepCopyInto(out) - return out -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/file-downloader.sh b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/file-downloader.sh deleted file mode 100755 index 8066b4e06..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/file-downloader.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# [~/helm-charts/nvidia]$ helm package kvm-driver-container-0.1.0 -# Successfully packaged chart and saved it to: /home/zvonkok/helm-charts/nvidia/kvm-driver-container-0.1.0.tgz -# [~/helm-charts/nvidia]$ helm repo index . --url=file:///$PWD - -FILE=${4/file:\/\//} - -echo $FILE >> /tmp/log.txt - -cat $FILE diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/file-helper.sh b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/file-helper.sh deleted file mode 100644 index f355d4e52..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/file-helper.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -# See e.g. https://github.com/viglesiasce/helm-gcs/tree/master/bin \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/plugin.yaml b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/plugin.yaml deleted file mode 100644 index 400f78c7c..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/file-proto/plugin.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: "file" -version: "0.1.0" -usage: "file:// protocol for charts and repositories." -description: "file:// protocol for charts and repositories." -command: "$HELM_PLUGIN_DIR/file-helper.sh" -downloaders: -- command: "file-downloader.sh" - protocols: - - "file" diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/plugins b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/plugins deleted file mode 120000 index 83aedfc9d..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/plugins/plugins +++ /dev/null @@ -1 +0,0 @@ -/zvonkok/github.com/zvonkok/helmer/plugins \ No newline at end of file diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/postrenderer.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/postrenderer.go deleted file mode 100644 index 8f31df684..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/postrenderer.go +++ /dev/null @@ -1,68 +0,0 @@ -package helmer - -import ( - "bytes" - "errors" - "fmt" - "os" - "os/exec" -) - -func check(e error) { - if e != nil { - panic(e) - } -} - -func mkdir(path string) error { - if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { - err := os.MkdirAll(path, os.ModePerm) - if err != nil { - return err - } - } - return nil -} - -func (h *Helmer) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) { - - kustomizePath := "/kustomize/" - chart := h.Package.ReleaseName + "-" + h.Package.ChartSpec.Version - basePath := kustomizePath + chart + "/base/" - - err = mkdir(basePath) - check(err) - - var kustomization bytes.Buffer - - manifests := bytes.Split(renderedManifests.Bytes(), []byte("---")) - if len(manifests[0]) == 0 { - manifests = manifests[1:] - } - - kustomization.WriteString("resources:\n") - for i, manifest := range manifests { - // this cannot error per docs - name := fmt.Sprintf("resource-%d.yaml", i) - err := os.WriteFile(basePath+name, manifest, 0644) - check(err) - fmt.Fprintf(&kustomization, " - %s\n", name) - } - - kustomization.WriteString("\n") - kustomization.WriteString("commonLabels:\n") - kustomization.WriteString(" app.trailblazer.nvidia.com/owned-by: HelmOrchard\n") - - err = os.WriteFile(basePath+"kustomization.yaml", kustomization.Bytes(), 0644) - check(err) - - kustomize := exec.Command("kustomize", "build", basePath) - out, err := kustomize.Output() - check(err) - - // otherwise, print the output from running the command - //klog.Info("Output: ", string(out)) - renderedManifests = bytes.NewBuffer(out) - - return renderedManifests, nil -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/repo.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/repo.go deleted file mode 100644 index d6dc642fe..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/repo.go +++ /dev/null @@ -1,17 +0,0 @@ -package helmer - -import "helm.sh/helm/v3/pkg/repo" - -func (in *repoEntry) DeepCopyInto(out *repo.Entry) *repo.Entry { - out.Name = in.Name - out.URL = in.URL - out.Username = in.Username - out.Password = in.Password - out.CertFile = in.CertFile - out.KeyFile = in.KeyFile - out.CAFile = in.CAFile - out.InsecureSkipTLSverify = in.InsecureSkipTLSverify - out.PassCredentialsAll = in.PassCredentialsAll - - return out -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/types.go b/deploy/k8s-operator/kube-trailblazer/pkg/helmer/types.go deleted file mode 100644 index cac21c615..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/helmer/types.go +++ /dev/null @@ -1,150 +0,0 @@ -package helmer - -import ( - "time" - - helmclient "github.com/mittwald/go-helm-client" - "github.com/mittwald/go-helm-client/values" - "github.com/nvidia/kube-trailblazer/pkg/clients" - "helm.sh/helm/v3/pkg/chartutil" -) - -// Type Guard asserting that Helmer satisfies the Helmer interface. -var _ Interface = &Helmer{} - -// Helmer describes the resource to be built -type Helmer struct { - Package HelmPackage `json:"helmArbor"` - Client helmclient.Client `json:"helmClient"` - Options helmclient.GenericHelmOptions `json:"helmOptions"` - KubeClient clients.ClientsInterface `json:"kubeClient"` - Debug bool `json:"debug"` -} - -// Entry represents a collection of parameters for chart repository, since -// we cannot annotate the internal helm struct we're doing it here -type repoEntry struct { - // +kubebuilder:validation:Optional - Name string `json:"name"` - URL string `json:"url"` - // +kubebuilder:validation:Optional - Username string `json:"username"` - // +kubebuilder:validation:Optional - Password string `json:"password"` - // +kubebuilder:validation:Optional - CertFile string `json:"certFile"` - // +kubebuilder:validation:Optional - KeyFile string `json:"keyFile"` - // +kubebuilder:validation:Optional - CAFile string `json:"caFile"` - // +kubebuilder:validation:Optional - InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"` - // +kubebuilder:validation:Optional - PassCredentialsAll bool `json:"pass_credentials_all"` -} -type chartSpec struct { - // +kubebuilder:validation:Optional - ReleaseName string `json:"release"` - ChartName string `json:"chart"` - // Namespace where the chart release is deployed. - // Note that helmclient.Options.Namespace should ideally match the namespace configured here. - // +kubebuilder:validation:Optional - Namespace string `json:"namespace"` - // ValuesYaml is the values.yaml content. - // use string instead of map[string]interface{} - // https://github.com/kubernetes-sigs/kubebuilder/issues/528#issuecomment-466449483 - // and https://github.com/kubernetes-sigs/controller-tools/pull/317 - // +optional - ValuesYaml string `json:"valuesYaml,omitempty"` - // Specify values similar to the cli - // +optional - ValuesOptions values.Options `json:"valuesOptions,omitempty"` - // Version of the chart release. - // +optional - Version string `json:"version,omitempty"` - // CreateNamespace indicates whether to create the namespace if it does not exist. - // +optional - CreateNamespace bool `json:"createNamespace,omitempty"` - // DisableHooks indicates whether to disable hooks. - // +optional - DisableHooks bool `json:"disableHooks,omitempty"` - // Replace indicates whether to replace the chart release if it already exists. - // +optional - Replace bool `json:"replace,omitempty"` - // Wait indicates whether to wait for the release to be deployed or not. - // +optional - Wait bool `json:"wait,omitempty"` - // WaitForJobs indicates whether to wait for completion of release Jobs before marking the release as successful. - // 'Wait' has to be specified for this to take effect. - // The timeout may be specified via the 'Timeout' field. - WaitForJobs bool `json:"waitForJobs,omitempty"` - // DependencyUpdate indicates whether to update the chart release if the dependencies have changed. - // +optional - DependencyUpdate bool `json:"dependencyUpdate,omitempty"` - // Timeout configures the time to wait for any individual Kubernetes operation (like Jobs for hooks). - // +optional - Timeout time.Duration `json:"timeout,omitempty"` - // GenerateName indicates that the release name should be generated. - // +optional - GenerateName bool `json:"generateName,omitempty"` - // NameTemplate is the template used to generate the release name if GenerateName is configured. - // +optional - NameTemplate string `json:"nameTemplate,omitempty"` - // Atomic indicates whether to install resources atomically. - // 'Wait' will automatically be set to true when using Atomic. - // +optional - Atomic bool `json:"atomic,omitempty"` - // SkipCRDs indicates whether to skip CRDs during installation. - // +optional - SkipCRDs bool `json:"skipCRDs,omitempty"` - // Upgrade indicates whether to perform a CRD upgrade during installation. - // +optional - UpgradeCRDs bool `json:"upgradeCRDs,omitempty"` - // SubNotes indicates whether to print sub-notes. - // +optional - SubNotes bool `json:"subNotes,omitempty"` - // Force indicates whether to force the operation. - // +optional - Force bool `json:"force,omitempty"` - // ResetValues indicates whether to reset the values.yaml file during installation. - // +optional - ResetValues bool `json:"resetValues,omitempty"` - // ReuseValues indicates whether to reuse the values.yaml file during installation. - // +optional - ReuseValues bool `json:"reuseValues,omitempty"` - // Recreate indicates whether to recreate the release if it already exists. - // +optional - Recreate bool `json:"recreate,omitempty"` - // MaxHistory limits the maximum number of revisions saved per release. - // +optional - MaxHistory int `json:"maxHistory,omitempty"` - // CleanupOnFail indicates whether to cleanup the release on failure. - // +optional - CleanupOnFail bool `json:"cleanupOnFail,omitempty"` - // DryRun indicates whether to perform a dry run. - // +optional - DryRun bool `json:"dryRun,omitempty"` - // Description specifies a custom description for the uninstalled release - // +optional - Description string `json:"description,omitempty"` - // KeepHistory indicates whether to retain or purge the release history during uninstall - // +optional - KeepHistory bool `json:"keepHistory,omitempty"` -} - -// A shelter of vines or branches or of latticework covered with climbing -// shrubs or vines, also latin for tree -type HelmPackage struct { - RepoEntry repoEntry `json:"repoEntry"` - ChartSpec chartSpec `json:"chartSpec"` - // +kubebuilder:validation:Optional - // +kubebuilder:validation:Schemaless - // +kubebuilder:pruning:PreserveUnknownFields - // +kubebuilder:validation:Type=object - // TODO ChartValues json.RawMessage `json:"chartValues"` - ChartValues chartutil.Values `json:"chartValues"` - // +kubebuilder:validation:Optional - ReleaseName string `json:"releaseName"` -} - -type Pipeline []HelmPackage diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/storage/mock_storage_api.go b/deploy/k8s-operator/kube-trailblazer/pkg/storage/mock_storage_api.go deleted file mode 100644 index 14004b58e..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/storage/mock_storage_api.go +++ /dev/null @@ -1,79 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: storage.go - -// Package storage is a generated GoMock package. -package storage - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - types "k8s.io/apimachinery/pkg/types" -) - -// MockStorage is a mock of Storage interface. -type MockStorage struct { - ctrl *gomock.Controller - recorder *MockStorageMockRecorder -} - -// MockStorageMockRecorder is the mock recorder for MockStorage. -type MockStorageMockRecorder struct { - mock *MockStorage -} - -// NewMockStorage creates a new mock instance. -func NewMockStorage(ctrl *gomock.Controller) *MockStorage { - mock := &MockStorage{ctrl: ctrl} - mock.recorder = &MockStorageMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockStorage) EXPECT() *MockStorageMockRecorder { - return m.recorder -} - -// CheckConfigMapEntry mocks base method. -func (m *MockStorage) CheckConfigMapEntry(arg0 context.Context, arg1 string, arg2 types.NamespacedName) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CheckConfigMapEntry", arg0, arg1, arg2) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CheckConfigMapEntry indicates an expected call of CheckConfigMapEntry. -func (mr *MockStorageMockRecorder) CheckConfigMapEntry(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckConfigMapEntry", reflect.TypeOf((*MockStorage)(nil).CheckConfigMapEntry), arg0, arg1, arg2) -} - -// DeleteConfigMapEntry mocks base method. -func (m *MockStorage) DeleteConfigMapEntry(arg0 context.Context, arg1 string, arg2 types.NamespacedName) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteConfigMapEntry", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteConfigMapEntry indicates an expected call of DeleteConfigMapEntry. -func (mr *MockStorageMockRecorder) DeleteConfigMapEntry(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfigMapEntry", reflect.TypeOf((*MockStorage)(nil).DeleteConfigMapEntry), arg0, arg1, arg2) -} - -// UpdateConfigMapEntry mocks base method. -func (m *MockStorage) UpdateConfigMapEntry(arg0 context.Context, arg1, arg2 string, arg3 types.NamespacedName) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateConfigMapEntry", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateConfigMapEntry indicates an expected call of UpdateConfigMapEntry. -func (mr *MockStorageMockRecorder) UpdateConfigMapEntry(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateConfigMapEntry", reflect.TypeOf((*MockStorage)(nil).UpdateConfigMapEntry), arg0, arg1, arg2, arg3) -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/storage/storage.go b/deploy/k8s-operator/kube-trailblazer/pkg/storage/storage.go deleted file mode 100644 index 82624ffde..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/storage/storage.go +++ /dev/null @@ -1,97 +0,0 @@ -package storage - -import ( - "context" - - "github.com/openshift-psap/special-resource-operator/pkg/clients" - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -//go:generate mockgen -source=storage.go -package=storage -destination=mock_storage_api.go - -type Storage interface { - CheckConfigMapEntry(context.Context, string, types.NamespacedName) (string, error) - UpdateConfigMapEntry(context.Context, string, string, types.NamespacedName) error - DeleteConfigMapEntry(context.Context, string, types.NamespacedName) error -} - -type storage struct { - kubeClient clients.ClientsInterface -} - -func NewStorage(kubeClient clients.ClientsInterface) Storage { - return &storage{kubeClient: kubeClient} -} - -func (s *storage) CheckConfigMapEntry(ctx context.Context, key string, ins types.NamespacedName) (string, error) { - cm, err := s.getConfigMap(ctx, ins.Namespace, ins.Name) - if err != nil { - return "", err - } - - return cm.Data[key], nil -} - -func (s *storage) UpdateConfigMapEntry(ctx context.Context, key string, value string, ins types.NamespacedName) error { - cm, err := s.getConfigMap(ctx, ins.Namespace, ins.Name) - if err != nil { - ctrl.LoggerFrom(ctx).Error(err, "Failed to get configmap to update an entry", "namespacedName", ins, "key", key, "value", value) - return err - } - - if cm.Data == nil { - cm.Data = make(map[string]string) - } - - if cm.Data[key] != value { - cm.Data[key] = value - - if err = s.updateObject(ctx, cm); err != nil { - ctrl.LoggerFrom(ctx).Error(err, "Failed to update configmap to update an entry", "namespacedName", ins, "key", key, "value", value) - return err - } - } - - return nil -} - -func (s *storage) DeleteConfigMapEntry(ctx context.Context, key string, ins types.NamespacedName) error { - cm, err := s.getConfigMap(ctx, ins.Namespace, ins.Name) - if err != nil { - ctrl.LoggerFrom(ctx).Error(err, "Failed to get configmap to remove an entry", "namespacedName", ins, "key", key) - return err - } - - if _, ok := cm.Data[key]; ok { - delete(cm.Data, key) - - if err = s.updateObject(ctx, cm); err != nil { - ctrl.LoggerFrom(ctx).Error(err, "Failed to update configmap to remove an entry", "namespacedName", ins, "key", key) - return err - } - } - - return nil -} - -func (s *storage) getConfigMap(ctx context.Context, namespace string, name string) (*v1.ConfigMap, error) { - cm := &v1.ConfigMap{} - dep := types.NamespacedName{Namespace: namespace, Name: name} - - err := s.kubeClient.Get(ctx, dep, cm) - - if apierrors.IsNotFound(err) { - ctrl.LoggerFrom(ctx).Error(err, "Failed to get configmap", "cmNamespace", namespace, "cmName", name) - return nil, err - } - - return cm, err -} - -func (s *storage) updateObject(ctx context.Context, cm client.Object) error { - return s.kubeClient.Update(ctx, cm) -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/storage/storage_test.go b/deploy/k8s-operator/kube-trailblazer/pkg/storage/storage_test.go deleted file mode 100644 index bf05495eb..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/storage/storage_test.go +++ /dev/null @@ -1,184 +0,0 @@ -package storage_test - -import ( - "context" - "testing" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/openshift-psap/special-resource-operator/pkg/clients" - "github.com/openshift-psap/special-resource-operator/pkg/storage" - v1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" -) - -const ( - namespaceName = "test-ns" - resourceName = "test-resource" -) - -var ( - ctrl *gomock.Controller - mockClient *clients.MockClientsInterface - notFound = k8serrors.NewNotFound(v1.Resource("configmap"), resourceName) - nsn = types.NamespacedName{Namespace: namespaceName, Name: resourceName} - cmMatcher = gomock.AssignableToTypeOf(&v1.ConfigMap{}) -) - -func TestStorage(t *testing.T) { - RegisterFailHandler(Fail) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockClient = clients.NewMockClientsInterface(ctrl) - }) - - AfterEach(func() { - ctrl.Finish() - }) - - RunSpecs(t, "Storage Suite") -} - -var _ = Describe("storage_CheckConfigMapEntry", func() { - const key = "test-key" - - It("should return an error with no ConfigMap present", func() { - mockClient. - EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}). - Return(notFound) - - _, err := storage.NewStorage(mockClient).CheckConfigMapEntry(context.TODO(), key, nsn) - Expect(err).To(HaveOccurred()) - }) - - It("should not return an error with an empty ConfigMap", func() { - mockClient. - EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}) - - _, err := storage.NewStorage(mockClient).CheckConfigMapEntry(context.TODO(), key, nsn) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should return the expected value with a good ConfigMap", func() { - const data = "test-data" - - mockClient. - EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}). - Do(func(_ context.Context, _ types.NamespacedName, cm *v1.ConfigMap) { - cm.Data = map[string]string{key: data} - }) - - v, err := storage.NewStorage(mockClient).CheckConfigMapEntry(context.TODO(), key, nsn) - - Expect(err).NotTo(HaveOccurred()) - Expect(v).To(Equal(data)) - }) -}) - -var _ = Describe("UpdateConfigMapEntry", func() { - It("should return an error when the ConfigMap does not exist", func() { - mockClient. - EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}). - Return(notFound) - - err := storage.NewStorage(mockClient).UpdateConfigMapEntry(context.TODO(), "any-key", "any-value", nsn) - Expect(err).To(HaveOccurred()) - }) - - It("set a key that does not already exist", func() { - const ( - key = "key" - value = "value" - ) - - gomock.InOrder( - mockClient.EXPECT().Get(context.TODO(), nsn, &v1.ConfigMap{}), - mockClient.EXPECT(). - Update(context.TODO(), cmMatcher). - Do(func(_ context.Context, cm *v1.ConfigMap) { - Expect(cm.Data).To(HaveKeyWithValue(key, value)) - }), - ) - - err := storage.NewStorage(mockClient).UpdateConfigMapEntry(context.TODO(), key, value, nsn) - Expect(err).NotTo(HaveOccurred()) - }) - - It("set a key that already exists", func() { - const ( - key = "key" - newValue = "new-value" - ) - - gomock.InOrder( - mockClient.EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}). - Do(func(_ context.Context, _ types.NamespacedName, cm *v1.ConfigMap) { - cm.Data = map[string]string{key: "oldvalue"} - }), - mockClient.EXPECT(). - Update(context.TODO(), cmMatcher). - Do(func(_ context.Context, cm *v1.ConfigMap) { - Expect(cm.Data).To(HaveKeyWithValue(key, newValue)) - }), - ) - - err := storage.NewStorage(mockClient).UpdateConfigMapEntry(context.TODO(), key, newValue, nsn) - Expect(err).NotTo(HaveOccurred()) - }) -}) - -var _ = Describe("DeleteConfigMapEntry", func() { - It("should return an error when the ConfigMap does not exist", func() { - mockClient. - EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}). - Return(notFound) - - err := storage.NewStorage(mockClient).DeleteConfigMapEntry(context.TODO(), "any-key", nsn) - Expect(err).To(HaveOccurred()) - }) - - It("should not return an error when the key does not exist", func() { - mockClient. - EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}) - - err := storage.NewStorage(mockClient).DeleteConfigMapEntry(context.TODO(), "some-other-key", nsn) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should delete the key when the key exists", func() { - const ( - key = "key" - otherKey = "other-key" - value = "value" - ) - - data := map[string]string{key: value, otherKey: "other-value"} - - gomock.InOrder( - mockClient.EXPECT(). - Get(context.TODO(), nsn, &v1.ConfigMap{}). - Do(func(_ context.Context, _ types.NamespacedName, cm *v1.ConfigMap) { - cm.Data = data - }), - mockClient.EXPECT(). - Update(context.TODO(), cmMatcher). - Do(func(_ context.Context, cm *v1.ConfigMap) { - Expect(cm.Data).NotTo(HaveKey(otherKey)) - Expect(cm.Data).To(HaveKeyWithValue(key, value)) - }), - ) - - err := storage.NewStorage(mockClient).DeleteConfigMapEntry(context.TODO(), otherKey, nsn) - Expect(err).NotTo(HaveOccurred()) - }) -}) diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/utils/hash.go b/deploy/k8s-operator/kube-trailblazer/pkg/utils/hash.go deleted file mode 100644 index a00f33d3d..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/utils/hash.go +++ /dev/null @@ -1,17 +0,0 @@ -package utils - -import ( - "fmt" - "hash/fnv" - - "github.com/pkg/errors" -) - -// FNV64a returns a 64bit hash -func FNV64a(s string) (string, error) { - h := fnv.New64a() - if _, err := h.Write([]byte(s)); err != nil { - return "", errors.Wrap(err, "[FNV64a]\tcould not create hash") - } - return fmt.Sprintf("%x", h.Sum64()), nil -} diff --git a/deploy/k8s-operator/kube-trailblazer/pkg/utils/rbac.go b/deploy/k8s-operator/kube-trailblazer/pkg/utils/rbac.go deleted file mode 100644 index 4e68c9b04..000000000 --- a/deploy/k8s-operator/kube-trailblazer/pkg/utils/rbac.go +++ /dev/null @@ -1,128 +0,0 @@ -package utils - -// +kubebuilder:rbac:groups=sro.openshift.io,resources=specialresources,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=sro.openshift.io,resources=specialresources/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=sro.openshift.io,resources=specialresources/finalizers,verbs=get;update;patch -// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=pods/log,verbs=get -// +kubebuilder:rbac:groups=apps,resources=daemonsets,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=config.openshift.io,resources=clusterversions,verbs=get -// +kubebuilder:rbac:groups=config.openshift.io,resources=proxies,verbs=get;list -// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=use;get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=image.openshift.io,resources=imagestreams,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=image.openshift.io,resources=imagestreams/finalizers,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=image.openshift.io,resources=imagestreams/layers,verbs=get -// +kubebuilder:rbac:groups=core,resources=imagestreams/layers,verbs=get -// +kubebuilder:rbac:groups=build.openshift.io,resources=buildconfigs,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=build.openshift.io,resources=builds,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=events,verbs=list;watch;create;update;patch;delete;get -// +kubebuilder:rbac:groups=core,resources=persistentvolumeclaims,verbs=get;list;watch;update; -// +kubebuilder:rbac:groups=core,resources=persistentvolumes,verbs=get;list;watch;create;delete;update;patch -// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;watch;create;update;delete -// +kubebuilder:rbac:groups=storage.k8s.io,resources=csinodes,verbs=get;list;watch -// +kubebuilder:rbac:groups=storage.k8s.io,resources=storageclasses,verbs=watch;get;list -// +kubebuilder:rbac:groups=storage.k8s.io,resources=csidrivers,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=endpoints,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=prometheusrules,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=cert-manager.io,resources=issuers,verbs=get;list;watch;create;update;patch;delete;deletecollection -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificates,verbs=get;list;watch;create;update;patch;delete;deletecollection -// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=persistentvolumeclaims,verbs=create;patch;delete -// +kubebuilder:rbac:groups=core,resources=services/finalizers,verbs=create;delete;get;list;update;patch;delete;watch -// +kubebuilder:rbac:groups=apps,resources=deployments/finalizers,resourceNames=shipwright-build,verbs=update -// +kubebuilder:rbac:groups=apps,resources=replicasets,verbs=create;delete;get;list;patch;update;watch;get -// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=shipwright.io,resources=*,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=shipwright.io,resources=buildruns,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=shipwright.io,resources=buildstrategies,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=shipwright.io,resources=clusterbuildstrategies,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=tekton.dev,resources=taskruns,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=tekton.dev,resources=tasks,verbs=create;delete;get;list;patch;update;watch -// +kubebuilder:rbac:groups=storage.k8s.io,resources=volumeattachments,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotclasses,verbs=get;list;watch -// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshots,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotcontents,verbs=create;get;list;watch;update;delete -// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshots/status,verbs=create;get;list;watch;update;delete -// +kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotcontents/status,verbs=create;get;list;watch;update;delete -// +kubebuilder:rbac:groups=csi.storage.k8s.io,resources=csidrivers,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=persistentvolumeclaims/status,verbs=get;list;watch;create;delete;update;patch -// +kubebuilder:rbac:groups=operators.coreos.com,resources=operatorgroups,verbs=get;list;watch;create;delete;update;patch -// +kubebuilder:rbac:groups=operators.coreos.com,resources=subscriptions,verbs=get;list;watch;create;delete;update;patch -// +kubebuilder:rbac:groups=operator.cert-manager.io,resources=certmanagers,verbs=get;list;watch;create;delete;update;patch -// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=mutatingwebhookconfigurations,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingwebhookconfigurations,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=apiregistration.k8s.io,resources=apiservices,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=auditregistration.k8s.io,resources=auditsinks,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=cert-manager.io,resources=issuers/status,verbs=update -// +kubebuilder:rbac:groups=cert-manager.io,resources=clusterissuers/status,verbs=update -// +kubebuilder:rbac:groups=cert-manager.io,resources=clusterissuers,verbs=get;update;list;watch;deletecollection -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificaterequests,verbs=get;update;list;watch;delete -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificaterequests/finalizers,verbs=update -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificaterequests/status,verbs=update -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificates/finalizers,verbs=update -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificates/status,verbs=update -// +kubebuilder:rbac:groups=acme.cert-manager.io,resources=orders,verbs=create;delete;get;list;watch;update;patch;deletecollection -// +kubebuilder:rbac:groups=acme.cert-manager.io,resources=challenges,verbs=create;delete;get;list;watch;update;patch;deletecollection -// +kubebuilder:rbac:groups=acme.cert-manager.io,resources=orders/finalizers,verbs=update -// +kubebuilder:rbac:groups=acme.cert-manager.io,resources=orders/status,verbs=update -// +kubebuilder:rbac:groups=acme.cert-manager.io,resources=challenges/finalizers,verbs=update -// +kubebuilder:rbac:groups=acme.cert-manager.io,resources=challenges/status,verbs=update -// +kubebuilder:rbac:groups=networking.k8s.io,resources=ingresses,verbs=get;list;watch;create;delete;update -// +kubebuilder:rbac:groups=networking.k8s.io,resources=ingresses/finalizers,verbs=update -// +kubebuilder:rbac:groups=route.openshift.io,resources=routes/custom-host,verbs=create -// +kubebuilder:rbac:groups=cert-manager.io,resources=certificaterequests,verbs=create;patch;deletecollection -// +kubebuilder:rbac:groups=cert-manager.io,resources=signers,resourceNames=clusterissuers.cert-manager.io/*,verbs=approve -// +kubebuilder:rbac:groups=cert-manager.io,resources=signers,resourceNames=issuers.cert-manager.io/*,verbs=approve -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=certificatesigningrequests/status,verbs=update -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=signers,resourceNames=clusterissuers.cert-manager.io/*,verbs=sign -// +kubebuilder:rbac:groups=certificates.k8s.io,resources=signers,resourceNames=issuers.cert-manager.io/*,verbs=sign -// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,resourceNames=cert-manager-cainjector-leader-election,verbs=patch -// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,resourceNames=cert-manager-cainjector-election-core,verbs=patch -// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,resourceNames=cert-manager-cainjector-leader-election-core,verbs=patch -// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,resourceNames=cert-manager-controller,verbs=patch -// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=mutatingwebhookconfigurations,verbs=create;get;list;watch;update;delete;patch -// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingwebhookconfigurations,verbs=create;get;list;watch;update;delete;patch -// +kubebuilder:rbac:groups=*,resources=cronjobs,verbs=get;delete;update;list;watch;patch -// +kubebuilder:rbac:groups=*,resources=daemonsets,verbs=get -// +kubebuilder:rbac:groups=*,resources=deployments,verbs=get -// +kubebuilder:rbac:groups=*,resources=imagepolicies,verbs=get;update;delete -// +kubebuilder:rbac:groups=*,resources=jobs,verbs=get;create;delete;update;list;watch;patch -// +kubebuilder:rbac:groups=*,resources=mutatingwebhookconfigurations,verbs=get -// +kubebuilder:rbac:groups=*,resources=pods,verbs=get -// +kubebuilder:rbac:groups=*,resources=replicacontrollers,verbs=get -// +kubebuilder:rbac:groups=*,resources=replicasets,verbs=get -// +kubebuilder:rbac:groups=*,resources=statefulsets,verbs=get -// +kubebuilder:rbac:groups=connaisseur.policy,resources=imagepolicies,verbs=create -// +kubebuilder:rbac:groups=admissionregistration.k8s.io/v1beta1,resources=mutatingwebhookconfigurations,verbs=create;delete;update;list -// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=watch;list -// +kubebuilder:rbac:groups="",resources=nodes/finalizers,verbs=update -// +kubebuilder:rbac:groups="",resources=nodes/status,verbs=update;patch -// +kubebuilder:rbac:groups="",resources=pods,verbs=deletecollection -// +kubebuilder:rbac:groups="",resources=podtemplates,verbs=list;watch;get;create;update -// +kubebuilder:rbac:groups="",resources=podtemplates/finalizers,verbs=update -// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=list;watch;get;create;update;patch;delete -// +kubebuilder:rbac:groups=batch,resources=jobs/finalizers,verbs=update -// +kubebuilder:rbac:groups=extensions,resources=jobs,verbs=list;watch;get;create;update;patch;delete -// +kubebuilder:rbac:groups=networking.x-k8s.io,resources=httproutes,verbs=get;list;watch;create;update;delete -// +kubebuilder:rbac:groups=networking.x-k8s.io,resources=gateways,verbs=get;list;watch -// +kubebuilder:rbac:groups=networking.x-k8s.io,resources=gateways/finalizers,verbs=update -// +kubebuilder:rbac:groups=networking.x-k8s.io,resources=httproutes/finalisers,verbs=update -// +kubebuilder:rbac:groups=infoscale.veritas.com,resources=infoscaleclusters,verbs=update;patch;get;list -// +kubebuilder:rbac:groups=fpga.silicom.dk,resources=*,verbs=list;watch;get;create;update;patch;delete -// +kubebuilder:rbac:groups=sts.silicom.com,resources=*,verbs=list;watch;get;create;update;patch;delete diff --git a/deploy/k8s-operator/kube-trailblazer/rag-llm-pipeline.yaml b/deploy/k8s-operator/kube-trailblazer/rag-llm-pipeline.yaml deleted file mode 100644 index f2267975d..000000000 --- a/deploy/k8s-operator/kube-trailblazer/rag-llm-pipeline.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: package.nvidia.com/v1alpha1 -kind: HelmPipeline -metadata: - name: rag-llm-pipeline -spec: - pipeline: - - repoEntry: - url: "file:///helm-charts/staging" - chartSpec: - chart: "rag-llm-pipeline" - chartValues: - triton: - modelDirectory: "/zvonkok/model/llama2_13b_chat_hf_v1/" - images: - registry: - ImagePullSecret: - password: ${NVCR_TOKEN} diff --git a/docs/api-catalog.md b/docs/api-catalog.md index feb5d371a..8a8028d76 100644 --- a/docs/api-catalog.md +++ b/docs/api-catalog.md @@ -28,7 +28,7 @@ backlinks: none ## Example Features This example deploys a developer RAG pipeline for chat Q&A and serves inferencing from an NVIDIA API Catalog endpoint -instead of NVIDIA Triton Inference Server, a local Llama 2 model, or local GPUs. +instead of a local inference server, a local model, or local GPUs. Developers get free credits for 10K requests to any of the available models. @@ -42,12 +42,22 @@ Developers get free credits for 10K requests to any of the available models. - Multi-GPU - TRT-LLM - Model Location - - Triton + - NIM for LLMs - Vector Database -* - ai-mixtral-8x7b-instruct - - ai-embed-qa-4 - - Langchain +* - ai-llama3-70b + - snowflake/arctic-embed-l + - LangChain + - QA chatbot + - NO + - NO + - API Catalog + - NO + - Milvus + +* - ai-llama3-8b + - snowflake/arctic-embed-l + - LlamaIndex - QA chatbot - NO - NO @@ -81,6 +91,14 @@ The following figure shows the sample topology: - Install Docker Engine and Docker Compose. Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). +- Login to Nvidia's docker registry. Please refer to [instructions](https://docs.nvidia.com/ngc/gpu-cloud/ngc-overview/index.html) to create account and generate NGC API key. This is needed for pulling in the secure base container used by all the examples. + + ```console + $ docker login nvcr.io + Username: $oauthtoken + Password: + ``` + - Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). @@ -101,7 +119,7 @@ The following figure shows the sample topology: % end-prerequisites -## Get an API Key for the Mixtral 8x7B Instruct API Endpoint +## Get an API Key for the Accessing Models on the API Catalog % api-key-start @@ -110,13 +128,13 @@ You can use different model API endpoints with the same API key. 1. Navigate to . -2. Find the **Mixtral 8x7B Instruct** card and click the card. +2. Find the **Llama 3 70B Instruct** card and click the card. - ![Mixtral 8x7B Instruct model card](./images/mixtral-8x7b-instruct.png) + ![Llama 3 70B Instruct model card](./images/llama3-70b-instruct-model-card.png) 3. Click **Get API Key**. - ![API section of the model page.](./images/image8.png) + ![API section of the model page.](./images/llama3-70b-instruct-get-api-key.png) 4. Click **Generate Key**. @@ -125,7 +143,7 @@ You can use different model API endpoints with the same API key. 5. Click **Copy Key** and then save the API key. The key begins with the letters nvapi-. - ![Key Generated widnow.](./images/key-generated.png) + ![Key Generated window.](./images/key-generated.png) % api-key-end @@ -143,13 +161,19 @@ You can use different model API endpoints with the same API key. 2. From the root of the repository, build the containers: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-api-catalog-text-chatbot.yaml build + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/rag-app-api-catalog-text-chatbot.yaml \ + build ``` 3. Start the containers: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-api-catalog-text-chatbot.yaml up -d + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/rag-app-api-catalog-text-chatbot.yaml \ + up -d ``` *Example Output* @@ -163,7 +187,11 @@ You can use different model API endpoints with the same API key. 4. Start the Milvus vector database: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-vectordb.yaml \ + --profile llm-embedding \ + up -d milvus ``` *Example Output* @@ -191,10 +219,64 @@ You can use different model API endpoints with the same API key. 57a068d62fbb milvus-etcd Up 3 minutes (healthy) ``` +## Using an Alternative Inference Model + +You can specify the model to use in the `APP_LLM_MODELNAME` environment variable when you start the Chain Server. +The following sample command uses the Mistral AI Mixtral 8x7B Instruct model. + +```console +$ APP_LLM_MODELNAME='mistralai/mixtral-8x7b-instruct-v0.1' docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/rag-app-api-catalog-text-chatbot.yaml \ + up -d +``` + +You can determine the available model names using one of the following methods: + +- Browse the models at . + View the sample Python code and get the model name from the `model` argument to the `client.chat.completions.create` method. +- Install the [langchain-nvidia-ai-endpoints](https://pypi.org/project/langchain-nvidia-ai-endpoints/) Python package from PyPi. + Use the `get_available_models()` method to list the models. + Refer to the preceding web page for sample code to list the models. + +## Using the LlamaIndex Data Framework + +As an alternative to the LangChain based Chain Server, you can build and run a LlamaIndex based Chain Server. + +This example also starts a JupyterLab server on port 8888. + +1. After meeting the [](#prerequisites), build the containers: + + ```console + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/rag-app-text-chatbot.yaml \ + build + ``` + +1. Start the containers: + + ```console + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/rag-app-text-chatbot.yaml \ + up -d + ``` + +1. Start the Milvus vector database: + + ```console + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-vectordb.yaml \ + --profile llm-embedding \ + up -d milvus + ``` + ## Next Steps - Access the web interface for the chat server. Refer to [](./using-sample-web-application.md) for information about using the web interface. - [](./vector-database.md) - Stop the containers by running `docker compose -f deploy/compose/rag-app-api-catalog-text-chatbot.yaml down` and - `docker compose -f deploy/compose/docker-compose-vectordb.yaml down`. + `docker compose -f deploy/compose/docker-compose-vectordb.yaml --profile llm-embedding down`. diff --git a/docs/architecture.md b/docs/architecture.md index 71f4f7a82..198bac04f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -29,66 +29,72 @@ backlinks: none The default sample deployment contains: -- [NVIDIA NeMo Framework Inference Server](https://docs.nvidia.com/nemo-framework/user-guide/latest/index.html) - part of NVIDIA AI Enterprise solution -- [NVIDIA TensorRT-LLM](https://developer.nvidia.com/tensorrt) - for low latency and high throughput inference for LLMs -- [LangChain](https://github.com/langchain-ai/langchain/) and [LlamaIndex](https://www.llamaindex.ai/) for combining language model components and easily constructing question-answering from a company's database -- [Sample Jupyter Notebooks](jupyter-server.md) and [chat bot web application/API calls](./frontend.md) so that you can test the chat system in an interactive manner -- [Milvus](https://milvus.io/docs/install_standalone-docker.md) - Generated embeddings are stored in a vector database. The vector DB used in this workflow is Milvus. Milvus is an open-source vector database capable of NVIDIA GPU-accelerated vector searches. -- [UAE-Large-V1 model](https://huggingface.co/WhereIsAI/UAE-Large-V1) from Hugging Face to generate the embeddings. -- [Llama2](https://github.com/facebookresearch/llama/), an open source model from Meta, to formulate natural responses. +- Inference and embedding are performed by accessing model endpoints running on NVIDIA API Catalog. -This sample deployment is a reference for you to build your own enterprise AI solution with minimal effort. -The software components are used to deploy models and inference pipeline, integrated together with the additional components as indicated in the following diagram: + Most examples use the [Meta Llama 3 70B Instruct](https://build.ngc.nvidia.com/meta/llama3-70b) model + for inference and the [Snowflake Arctic Embed L](https://build.ngc.nvidia.com/snowflake/arctic-embed-l) + model for embedding. -![Diagram](./images/image0.png) + Alternatively, you can deploy NVIDIA NIM for LLMs and NVIDIA NeMo Retriever Embedding microservice + to use local models and local GPUs. + Refer to the [](nim-llms.md) example for more information. + +- A Chain Server uses [LangChain](https://github.com/langchain-ai/langchain/) and [LlamaIndex](https://www.llamaindex.ai/) for combining language model components and easily constructing question-answering from a company's database. + +- [Sample Jupyter Notebooks](jupyter-server.md) and [](./frontend.md) so that you can test the chat system in an interactive manner. + +- [Milvus](https://milvus.io/docs/install_standalone-docker.md) or [pgvector](https://github.com/pgvector/pgvector) - Embeddings are stored in a vector database. Milvus is an open-source vector database capable of NVIDIA GPU-accelerated vector searches. + +The sample deployment is a reference for you to build your own enterprise AI solution with minimal effort. ## NVIDIA AI Components The sample deployment uses a variety of NVIDIA AI components to customize and deploy the RAG-based chat bot example. - [NVIDIA TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM) -- [NVIDIA NeMo Inference Container](https://developer.nvidia.com/nemo) +- [NVIDIA NIM for LLMs](https://docs.nvidia.com/nim/large-language-models/latest/index.html) ### NVIDIA TensorRT-LLM Optimization -An LLM can be optimized using TensorRT-LLM. NVIDIA NeMo uses TensorRT for LLMs (TensorRT-LLM), for deployment which accelerates and maximizes inference performance on the latest LLMs. -The sample deployment leverages a Llama 2 (13B parameters) chat model. -The foundational model is converted to TensorRT format using TensorRT-LLM for optimized inference. +An LLM can be optimized using TensorRT-LLM. +NVIDIA NIM for LLMs uses TensorRT for LLMs (TensorRT-LLM) to accelerate and maximize inference performance on the latest LLMs. +The sample deployment deploys a Llama 3 8B parameter chat model that TensorRT-LLM optimizes for inference. -### NVIDIA NeMo Framework Inference Container +### NVIDIA NIM for LLMs Container -With NeMo Framework Inference Container, the optimized LLM can be deployed for high-performance, cost-effective, and low-latency inference. NeMo Framework Inference Container contains modules and scripts to help exporting LLM models to [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM) and deploying them to [Triton Inference Server](https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/index.html) with easy-to-use APIs. +The NVIDIA NIM for LLMs container simplifies deployment and provides high-performance, cost-effective, and low-latency inference. +Software in the container determines your GPU hardware and determines whether to use the TensorRT-LLM backend or the vLLM backend. ## Inference Pipeline -To get started with the inferencing pipeline, we connect the customized LLM to a sample proprietary data source. -This knowledge can come in many forms: product specifications, HR documents, or finance spreadsheets. +To get started with the inferencing pipeline, we connect the LLM to a sample vector database. +You can upload documents and embeddings of the documents are stored in the vector database to augment the responses to your queries. +The knowledge in the vector database can come in many forms: product specifications, HR documents, or finance spreadsheets. Enhancing the model’s capabilities with this knowledge can be done with RAG. Because foundational LLMs are not trained on your proprietary enterprise data and are only trained up to a fixed point in time, they need to be augmented with additional data. RAG consists of two processes. First, *retrieval* of data from document repositories, databases, or APIs that are all outside of the foundational model’s knowledge. Second, *generation* of responses via inference. -The following graphic describes an overview of this inference pipeline: - -![Diagram](./images/image1.png) ## Document Ingestion and Retrieval RAG begins with a knowledge base of relevant up-to-date information. Because data within an enterprise is frequently updated, the ingestion of documents into a knowledge base is a recurring process and could be scheduled as a job. -Next, content from the knowledge base is passed to an embedding model such as UAE-Large-V1 that the sample deployment uses. +Next, content from the knowledge base is passed to an embedding model such as Snowflake Arctic Embedding L that the sample deployment uses. The embedding model converts the content to vectors, referred to as *embeddings*. Generating embeddings is a critical step in RAG. The embeddings provide dense numerical representations of textual information. -These embeddings are stored in a vector database, in this case Milvus, which is [RAFT accelerated](https://developer.nvidia.com/blog/accelerating-vector-search-using-gpu-powered-indexes-with-rapids-raft). +These embeddings are stored in a vector database. +The default database is Milvus, which is [RAFT accelerated](https://developer.nvidia.com/blog/accelerating-vector-search-using-gpu-powered-indexes-with-rapids-raft). +An alternative vector database is pgvector. ## User Query and Response Generation When a user query is sent to the inference server, it is converted to an embedding using the embedding model. -This is the same embedding model that is used to convert the documents in the knowledge base, UAE-Large-V1, in the case of this sample deployment. +This is the same embedding model that is used to convert the documents in the knowledge base. The database performs a similarity/semantic search to find the vectors that most closely resemble the user’s intent and provides them to the LLM as enhanced context. -Because Milvus is RAFT accelerated, the similarity serach is optimized on the GPU. +Because Milvus is RAFT accelerated, the similarity search is optimized on the GPU. Lastly, the LLM generates a full answer that is streamed to the user. This is all done with ease using [LangChain](https://github.com/langchain-ai/langchain/) and [LlamaIndex](https://www.llamaindex.ai). @@ -97,8 +103,8 @@ The following diagram illustrates the ingestion of documents and generation of r ![Diagram](./images/image2.png) LangChain enables you to write LLM wrappers for your own custom LLMs. -NVIDIA provides a sample wrapper for streaming responses from a TensorRT-LLM Llama 2 model running on Triton Inference Server. -This wrapper enables us to leverage LangChain’s standard interface for interacting with LLMs while still achieving vast performance speedup from TensorRT-LLM and scalable and flexible inference from Triton Inference Server. +NVIDIA provides a sample wrapper for streaming responses from an LLM running in NVIDIA NIM for LLMs. +This wrapper enables us to leverage LangChain’s standard interface for interacting with LLMs while still achieving vast performance speedup from TensorRT-LLM and scalable and flexible inference from NIM for LLMs. A sample chat bot web application is provided in the sample deployment so that you can test the chat system in an interactive manner. Requests to the chat system are wrapped in API calls, so these can be abstracted to other applications. @@ -111,23 +117,18 @@ In our sample deployment, we prompt our model to generate safe and polite respon ## LLM Inference Server -The LLM Inference Server uses models that are stored in a model repository. +The NVIDIA NIM for LLMs container downloads a model that is cached in a model repository. This repository is available locally to serve inference requests. -After they are available in Triton Inference Server, inference requests are sent from a client application. +After the container downloads the model, inference requests are sent from a client application. Python and C++ libraries provide APIs to simplify communication. -Clients send HTTP/REST requests directly to Triton Inference Server using HTTP/REST or gRPC protocols. - -Within the sample deployment, the Llama2 LLM was optimized using NVIDIA TensorRT for LLMs (TRT-LLM). -This software accelerates and maximizes inference performance on the latest LLMs. +Clients send HTTP/REST requests to NIM for LLMs using HTTP/REST or gRPC protocols. ## Vector DB Milvus is an open-source vector database built to power embedding similarity search and AI applications. The database makes unstructured data from API calls, PDFs, and other documents more accessible by storing them as embeddings. -When content from the knowledge base is passed to an embedding model, UAE-Large-V1, the model converts the content to vectors--referred to as *embeddings*. +When content from the knowledge base is passed to an embedding model, the model converts the content to vectors--referred to as *embeddings*. These embeddings are stored in the vector database. The sample deployment uses Milvus as the vector database. Milvus is an open-source vector database capable of NVIDIA GPU-accelerated vector searches. - -If needed, see Milvus's [documentation](https://milvus.io/docs/install_standalone-docker.md/) for how to configure a Docker Compose file for Milvus. diff --git a/docs/conf.py b/docs/conf.py index 4c39f6f2f..c568d1b29 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ this_year = date.today().year copyright = f"2023-{this_year}, NVIDIA Corporation" author = "NVIDIA Corporation" -release = "24.4.0" +release = "24.6.0" extensions = [ "sphinx_rtd_theme", diff --git a/docs/configuration.md b/docs/configuration.md index 4d14d1b64..00905d33c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -31,18 +31,6 @@ The following sections identify the environment variables and parameters that ar You can set environment variables in the `deploy/compose/compose.env` file. -### LLM Server Configuration - -LLM Inference server hosts the Large Language Model (LLM) with Triton Inference Server backend. - -You can configure the server using the following environment variables: - -:MODEL_DIRECTORY: Specifies the path to the model directory where model checkpoints are stored. -:MODEL_ARCHITECTURE: Defines the architecture of the model used for deployment. -:MODEL_MAX_INPUT_LENGTH: Maximum allowed input length, with a default value of 3000. -:QUANTIZATION: Specifies to enable activation-aware quantization for the LLM. By default, quantization is not enabled. -:INFERENCE_GPU_COUNT: Specifies the GPUs to be used by Triton for model deployment, with the default setting being "all." - ### Milvus Milvus is the default vector database server. @@ -74,13 +62,10 @@ You can configure the server using the following environment variable: :APP_VECTORSTORE_URL: Specifies the URL of the vector database server. :APP_VECTORSTORE_NAME: Specifies the vendor name of the vector database. Values are `milvus` or `pgvector`. :COLLECTION_NAME: Specifies the example-specific collection in the vector database. -:APP_LLM_SERVERURL: Specifies the URL of Triton Inference Server. -:APP_LLM_MODELNAME: The model name used by the Triton server. +:APP_LLM_SERVERURL: Specifies the URL of NVIDIA NIM for LLMs. +:APP_LLM_MODELNAME: The model name used by NIM for LLMs. :APP_LLM_MODELENGINE: An enum that specifies the backend name hosting the model. Supported values are as follows: - - `triton-trt-llm` to use locally deployed LLM models. - - `nvidia-ai-endpoints` to use models hosted from NVIDIA API Catalog. + `nvidia-ai-endpoints` to use models hosted using NIM for LLMs in cloud based API Catalog or locally. :APP_RETRIEVER_TOPK: Number of relevant results to retrieve. The default value is `4`. :APP_RETRIEVER_SCORETHRESHOLD: The minimum confidence score for the retrieved values to be considered. The default value is `0.25`. :APP_PROMPTS_CHATTEMPLATE: Specifies the instructions to provide to the model. @@ -89,7 +74,7 @@ You can configure the server using the following environment variable: :APP_PROMPTS_RAGTEMPLATE: Specifies the instructions to provide to the model. The prompt is combined with the user-supplied query and then presented to the model. The chain server uses this prompt when the query uses a knowledge base. - +:LOGLEVEL: Set the logging verbosity level for the logs printed by container. Chain server uses the standard python logging module. Possible values are NOTSET, DEBUG, INFO, WARN, ERROR, CRITICAL. ### RAG Playground diff --git a/docs/developer-llm-operator/README.md b/docs/developer-llm-operator/README.md deleted file mode 100644 index 5ac398b2a..000000000 --- a/docs/developer-llm-operator/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -# NVIDIA Developer LLM Operator - -The NVIDIA Developer LLM Operator enables developers to -build RAG-LLM pipelines on Kubernetes and manage the lifecycle of the -components for a sample pipeline. - -The Operator manages the lifecycle of the following components: - -- **Jupyter Notebook server**: - The container includes sample notebooks to demonstrate a sample pipeline. - -- **Chatbot web application**: - The sample web application enables you to perform question and answering with the chatbot - and to upload PDF documents to form a knowledge base. - -- **Vector database**: - The sample pipeline uses Milvus to manage the embeddings generated by the LLM. - -- **NVIDIA Triton Inference Server**: - The server is configured with the NVIDIA Nemo Framework for working with LLMs. - -Refer to [Installing the Operator](./install.md) to get started. \ No newline at end of file diff --git a/docs/developer-llm-operator/install.md b/docs/developer-llm-operator/install.md deleted file mode 100644 index ba3df5169..000000000 --- a/docs/developer-llm-operator/install.md +++ /dev/null @@ -1,309 +0,0 @@ - - -# Installing the Operator - -## Prerequisites - -- You have a machine with one or more NVIDIA A100 80 GB or NVIDIA H100 GPUs. - If you have fewer than four GPUs, you can configure GPU time-slicing. - Time-slicing oversubscribes the GPUs to simulate the four GPUs that are required, - though at lower performance. - -- You have access to Docker and Docker Compose to build container images. - Refer to the [installation documentation](https://docs.docker.com/engine/install/ubuntu/) - for Ubuntu from the Docker documentation. - -- You have Kubernetes installed and running on the machine with Ubuntu 22.04 or 20.04. - Refer to the [Kubernetes documentation](https://kubernetes.io/docs/setup/) or - the [NVIDIA Cloud Native Stack repository](https://github.com/NVIDIA/cloud-native-stack/) - for more information. - -- You have access to Git and Git LFS to clone the repository to get access to the Dockerfile - and software for container images. - -- You downloaded a Llama2 chat model weights from Meta or HuggingFace. - Get the 13 billion or 7 billion parameter model. - - Request access to the model from [Meta](https://ai.meta.com/resources/models-and-libraries/llama-downloads/) - or refer to the [meta-llama/LLama-2-13b-chat-hf](https://huggingface.co/meta-llama/Llama-2-13b-chat-hf) - page from HuggingFace. - - The directory with the model is shared as a host path volume mount with the Triton Inference Server pod. - - -## Install the NVIDIA GPU Operator - -Use the NVIDIA GPU Operator to install, configure, and manage the NVIDIA GPU driver and -NVIDIA container runtime on the Kubernetes node. - -1. Add the NVIDIA Helm repository: - - ```console - $ helm repo add nvidia https://helm.ngc.nvidia.com/nvidia \ - && helm repo update - ``` - -1. Install the Operator: - - ```console - $ helm install --wait --generate-name \ - -n gpu-operator --create-namespace \ - nvidia/gpu-operator - ``` - -1. Optional: Configure GPU time-slicing if you have fewer than four GPUs. - - - Create a file, `time-slicing-config-all.yaml`, with the following content: - - ```yaml - apiVersion: v1 - kind: ConfigMap - metadata: - name: time-slicing-config-all - data: - any: |- - version: v1 - flags: - migStrategy: none - sharing: - timeSlicing: - resources: - - name: nvidia.com/gpu - replicas: 4 - ``` - - The sample configuration creates four *replicas* from each GPU on the node. - - - Add the config map to the Operator namespace: - - ```console - $ kubectl create -n gpu-operator -f time-slicing-config-all.yaml - ``` - - - Configure the device plugin with the config map and set the default time-slicing configuration: - - ```console - $ kubectl patch clusterpolicy/cluster-policy \ - -n gpu-operator --type merge \ - -p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config-all", "default": "any"}}}}' - ``` - - - Verify that at least `4` GPUs are allocatable: - - ```console - $ kubectl get nodes -l nvidia.com/gpu.present -o json | jq '.items[0].status.allocatable | with_entries(select(.key | startswith("nvidia.com/"))) | with_entries(select(.value != "0"))' - ``` - - *Example Output* - - ```json - { - "nvidia.com/gpu": "4" - } - ``` - -For more information or to adjust the configuration, refer to -[Install NVIDIA GPU Operator](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html#install-nvidia-gpu-operator) and -[Time-Slicing GPUs in Kubernetes](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-sharing.html) -in the NVIDIA GPU Operator documentation. - -## Install the Developer LLM Operator - -1. Get the Helm chart for the Operator: - - ```console - $ helm fetch https://helm.ngc.nvidia.com/nvidia/cloud-native/charts/developer-llm-operator-0.1.0.tgz - ``` - -1. Install the Operator: - - ```console - $ helm install --generate-name ./developer-llm-operator-0.1.0.tgz \ - -n kube-trailblazer-system --create-namespace - ``` - -1. Optional: Confirm the controller pod is running: - - ```console - $ kubectl get pods -n kube-trailblazer-system - ``` - - *Example Output* - - ```output - NAME READY STATUS RESTARTS AGE - kube-trailblazer-controller-manager-868bf8dc84-p2zgc 2/2 Running 2 (20h ago) 21h - ``` - -## Build the Container Images - -1. Clone the repository if you haven't already: - - ```console - $ git lfs clone https://github.com/NVIDIA/GenerativeAIExamples.git - ``` - -1. Build the container images: - - ```console - $ cd GenerativeAIExamples/deploy/compose - $ docker compose --env-file compose.env build - ``` - - Building the images requires several minutes. - -1. Start a local registry, tag the images, and push the images to the registry. - - - Start a local registry: - - ```console - $ docker run -d -p 5000:5000 --name registry registry:2.7 - ``` - - - Tag and push the images that are not publicly available: - - ```console - $ docker tag llm-inference-server localhost:5000/llm-inference-server - $ docker push localhost:5000/llm-inference-server - - $ docker tag chain-server localhost:5000/chain-server - $ docker push localhost:5000/chain-server - - $ docker tag llm-playground localhost:5000/llm-playground - $ docker push localhost:5000/llm-playground - - $ docker tag notebook-server localhost:5000/notebook-server - $ docker push localhost:5000/notebook-server - ``` - - - Optional: Confirm the images are available from the local registry: - - ```console - $ curl -sSL "http://localhost:5000/v2/_catalog" - ``` - - *Example Output* - - ```json - {"repositories":["chain-server","llm-inference-server","llm-playground","notebook-server"]} - ``` - -## Create a RAG-LLM Pipeline - -1. Create a file, such as `rag-llm-pipeline.yaml`, with contents like the following example: - - ```yaml - apiVersion: package.nvidia.com/v1alpha1 - kind: HelmPipeline - metadata: - name: rag-llm-pipeline - spec: - pipeline: - - repoEntry: - url: "file:///helm-charts/staging" - chartSpec: - chart: "rag-llm-pipeline" - chartValues: - triton: - modelDirectory: "/llama2_13b_chat_hf_v1/" - ``` - - Modify the `modelDirectory` value to match the location and name of the model directory - on the Kubernetes node. - -1. Apply the manifest: - - ```console - $ kubectl apply -n kube-trailblazer-system -f rag-llm-pipeline.yaml - ``` - - The Operator creates the `rag-llm-pipeline` namespace and creates deployments and services in the namespace. - Downloading the container images and starting the pods can require a few minutes. - -1. Optional: Monitor progress. - - - View the logs from the Operator controller pod: - - ```console - $ kubectl logs -n kube-trailblazer-system $(kubectl get pod -n kube-trailblazer-system -o=jsonpath='{.items[0].metadata.name}') - ``` - - - View the pods in the pipeline namespace: - - ```console - $ kubectl get pods -n rag-llm-pipeline - ``` - - *Example Output* - - ```output - NAME READY STATUS RESTARTS AGE - jupyter-notebook-server-6d6b46578d-98xdq 1/1 Running 0 21h - llm-playground-6fd649ff8f-r2hp6 1/1 Running 0 22h - milvu-etcd-6559759884-9rvpz 1/1 Running 0 22h - milvus-minio-6fc5b9bdd4-d7l4z 1/1 Running 0 22h - milvus-standalone-9bfb5d974-tsjtp 1/1 Running 0 22h - query-router-77499f5459-6jjr9 1/1 Running 0 22h - triton-inference-server-79d5c499b-26nqq 0/1 Running 0 22h - ``` - -1. View the services and node ports: - - ```console - $ kubectl get svc -n rag-llm-pipeline - ``` - - *Example Output* - - ```output - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - frontend-service NodePort 10.111.66.10 8090:30001/TCP 22h - jupyter-notebook-service NodePort 10.110.101.174 8888:30000/TCP 22h - llm ClusterIP 10.107.213.112 8001/TCP 22h - milvus ClusterIP 10.102.86.183 19530/TCP 22h - milvus-etcd ClusterIP 10.109.74.142 2379/TCP 22h - milvus-minio ClusterIP 10.103.238.28 9010/TCP 22h - query ClusterIP 10.110.199.69 8081/TCP 22h - ``` - - The output shows that the chat web application, `frontend-service`, is mapped to port `30001` - on the Kubernetes host through a node port. - The output also shows the Jupyter Notebook server is mapped to port `30000` on the host. - -## Access the Chat Web Application - -- Open a browser and access `http://localhost:30001` or replace localhost with the IP address - of the Kubernetes node. - - ![Chat web application](../rag/images/image4.jpg) - -- Upload a PDF file as a knowledge base for retrieval. - - - Access `http://localhost:30001/converse` and click **Knowledge Base**. - - - Browse to a local file and upload it to the web application. - - - When you return to the **Converse** tab to ask a question, enable the **Use knowledge base** checkbox. - -## Access the Jupyter Notebooks - -- Open a browser and access `http://localhost:30000` or replace localhost with the IP address - of the Kubernetes node. - - Browse and run the notebooks that are part of the container image. - diff --git a/docs/developer-llm-operator/uninstall.md b/docs/developer-llm-operator/uninstall.md deleted file mode 100644 index 5cd096a70..000000000 --- a/docs/developer-llm-operator/uninstall.md +++ /dev/null @@ -1,50 +0,0 @@ - - -# Uninstalling the Operator - -To uninstall the Operator, perform the following steps: - -1. Delete the RAG pipeline: - - ```console - $ kubectl delete helmpipeline -n kube-trailblazer-system rag-llm-pipeline - ``` - - *Example Output* - - ```output - helmpipeline.package.nvidia.com "rag-llm-pipeline" deleted - ``` - -1. Optional: Delete the namespace for the RAG pipeline: - - ```console - $ kubectl delete namespace rag-llm-pipeline - ``` - -1. Uninstall the Operator: - - ```console - $ helm delete -n kube-trailblazer-system $(helm list -n kube-trailblazer-system | grep developer-llm-operator | awk '{print $1}') - ``` - - *Example Output* - - ```output - release "developer-llm-operator-0-1705070979" uninstalled - ``` diff --git a/docs/evaluation.md b/docs/evaluation.md index 075f3f769..b7377e2c4 100644 --- a/docs/evaluation.md +++ b/docs/evaluation.md @@ -203,7 +203,7 @@ You can use different model API endpoints with the same API key. $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml build ``` -4. Start the milvus container: +4. Start the Milvus container: ```console $ docker compose -f deploy/compose/docker-compose-vectordb.yaml up -d milvus @@ -214,7 +214,8 @@ You can use different model API endpoints with the same API key. ```console $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml up -d ``` - NVIDIA Triton Inference Server can require 5 minutes to start. The `-d` flag starts the services in the background. + + The inference server can require 5 minutes to start. The `-d` flag starts the services in the background. *Example Output* diff --git a/docs/hf_model_download.md b/docs/hf_model_download.md deleted file mode 100644 index 216020c9b..000000000 --- a/docs/hf_model_download.md +++ /dev/null @@ -1,59 +0,0 @@ -## Downloading Model from huggingface - -- Visit the Hugging Face Models Hub at https://huggingface.co/models - -- Search for the "llama-2" model in search bar. -![Model Search](../rag/images/hf/Slide1.JPG) - -- Choose the specific model you wish to download; for instance, let's select "llama-2-13b-chat-hf." - -- If you haven't already, sign up or log in to your Hugging Face account. -![Signup Page](../rag/images/hf/Slide2.JPG) - -- Agree to the terms and conditions provided. -![T and C Page](../rag/images/hf/Slide3.JPG) - - -- Confirm that your request to access the repository is successful. -![Success](../rag/images/hf/Slide4.JPG) - -- Complete the meta form by clicking on the link `Meta website` link mentioned in the previous steps. -![Meta Form](../rag/images/hf/Slide5.JPG) - -- Navigate to the "Files" section, which displays the available files. If you don't have access, it will be indicated like below. -![Default files](../rag/images/hf/Slide6.JPG) - -- Upon obtaining the necessary permissions, you will see all the files associated with the model on Hugging Face. -![Files list](../rag/images/hf/Slide7.JPG) - -- Click on the three dots (...) next to the train. -![Files list](../rag/images/hf/Slide8.JPG) - -- Select "Clone repository," which will prompt the following: -![Files list](../rag/images/hf/Slide9.JPG) - -- Execute the provided command in your terminal. When prompted, enter your Hugging Face username and token. -![Files list](../rag/images/hf/download.png) - -- In the password section, insert your token. If you haven't generated a token, you can do so in the Hugging Face settings. -![Files list](../rag/images/hf/Slide11.JPG) - -- Access the "Access Tokens" section in the right panel. -![Files list](../rag/images/hf/Slide12.JPG) - -- Generate a new token or copy an existing one. -![Files list](../rag/images/hf/Slide13.JPG) - -- Paste the token into your terminal. -![Files list](../rag/images/hf/download.png) - -- You may be asked for your username and password multiple times; provide the required information. - -- The terminal will initiate the download process for the model. This may take some time as it involves downloading checkpoints. - -- Once the download is complete, you will be able to view the contents of the downloaded model. - - - - - diff --git a/docs/images/llama3-70b-instruct-get-api-key.png b/docs/images/llama3-70b-instruct-get-api-key.png new file mode 100644 index 000000000..4e186b0b1 Binary files /dev/null and b/docs/images/llama3-70b-instruct-get-api-key.png differ diff --git a/docs/images/llama3-70b-instruct-model-card.png b/docs/images/llama3-70b-instruct-model-card.png new file mode 100644 index 000000000..427ce27a9 Binary files /dev/null and b/docs/images/llama3-70b-instruct-model-card.png differ diff --git a/docs/images/llama3-8b-instruct-get-api-key.png b/docs/images/llama3-8b-instruct-get-api-key.png new file mode 100644 index 000000000..c59234952 Binary files /dev/null and b/docs/images/llama3-8b-instruct-get-api-key.png differ diff --git a/docs/images/llama3-8b-instruct-model-card.png b/docs/images/llama3-8b-instruct-model-card.png new file mode 100644 index 000000000..e0bdd4a61 Binary files /dev/null and b/docs/images/llama3-8b-instruct-model-card.png differ diff --git a/docs/images/local-gpus-topology.png b/docs/images/local-gpus-topology.png deleted file mode 100644 index c33a14eda..000000000 Binary files a/docs/images/local-gpus-topology.png and /dev/null differ diff --git a/docs/images/nim-llms-topology.png b/docs/images/nim-llms-topology.png new file mode 100644 index 000000000..f8ba2f971 Binary files /dev/null and b/docs/images/nim-llms-topology.png differ diff --git a/docs/index.md b/docs/index.md index ff493eca9..567ce7f18 100644 --- a/docs/index.md +++ b/docs/index.md @@ -43,100 +43,66 @@ The chat bot also supports uploading documents to create a knowledge base. - | Embedding - | Framework - | Description - - | Multi-GPU - - | TensorRT-LLM - | Model | Location - - | Triton - | Inference - | Server + - | NIM + | for + | LLMs - | Vector | Database - * - ai-mixtral-8x7b-instruct - - ai-embed-qa-4 + * - ai-llama3-70b + - snowflake-arctic-embed-l - LangChain - :doc:`api-catalog` - - NO - - NO - API Catalog - - NO + - No - Milvus or pgvector - * - llama-2 - - UAE-Large-V1 - - LlamaIndex - - :doc:`local-gpu` - - NO - - YES - - Local Model - - YES - - Milvus or pgvector - - * - llama-2 - - UAE-Large-V1 - - LlamaIndex - - :doc:`multi-gpu` - - YES - - YES - - Local Model - - YES - - Milvus or pgvector - - * - ai-llama2-70b - - ai-embed-qa-4 + * - ai-llama3-70b + - snowflake-arctic-embed-l - LangChain - :doc:`query-decomposition` - - NO - - NO - API Catalog - - NO + - No - Milvus or pgvector - * - llama2-7b - - UAE-Large-V1 - - LlamaIndex - - :doc:`quantized-llm-model` - - NO - - YES - - Local Model - - YES - - Milvus or pgvector + * - meta/llama3-70b-instruct for response generation - * - ai-llama3-70b for response generation - - ai-llama3-70b for PandasAI + meta/llama3-70b-instruct for PandasAI - Not Applicable - PandasAI - :doc:`structured-data` - - NO - - NO - API Catalog - - NO + - No - Not Applicable - * - ai-mixtral-8x7b-instruct for response generation + * - ai-llama3-8b for response generation ai-google-Deplot for graph to text conversion ai-Neva-22B for image to text conversion - - ai-embed-qa-4 + - snowflake-arctic-embed-l - Custom Python - :doc:`multimodal-data` - - NO - - NO - API Catalog - - NO + - No - Milvus or pgvector - * - ai-llama2-70b - - ai-embed-qa-4 + * - ai-llama3-8b + - snowflake-arctic-embed-l - LangChain - :doc:`multi-turn` - - NO - - NO - API Catalog - - NO + - No + - Milvus or pgvector + + * - meta-llama3-8b-instruct + - nv-embed-qa:4 + - LangChain + - :doc:`nim-llms` + - Local LLM + - Yes - Milvus or pgvector ``` @@ -145,7 +111,7 @@ The chat bot also supports uploading documents to create a knowledge base. ```{include} ../README.md :start-after: '## Open Source Integrations' -:end-before: '## Support, Feedback, and Contributing' +:end-before: '## Related NVIDIA Projects' ``` ```{toctree} @@ -156,10 +122,7 @@ The chat bot also supports uploading documents to create a knowledge base. About the RAG Pipelines support-matrix API Catalog Models -Local GPUs -Multi-GPU for Inference Query Decomposition -Quantized Model Structured Data Multimodal Data Multi-turn @@ -193,7 +156,6 @@ notebooks/* :hidden: architecture -llm-inference-server frontend jupyter-server chain-server diff --git a/docs/jupyter-server.md b/docs/jupyter-server.md index 94e7aee36..02042508f 100644 --- a/docs/jupyter-server.md +++ b/docs/jupyter-server.md @@ -31,60 +31,49 @@ The Jupyter notebooks provide guidance to building knowledge-augmented chat bots The following Jupyter notebooks are provided with the AI workflow for the default canonical RAG example: -- [LLM Streaming Client](../../notebooks/01-llm-streaming-client.ipynb) - - This notebook demonstrates how to use a client to stream responses from an LLM deployed to NVIDIA Triton Inference Server with NVIDIA TensorRT-LLM (TRT-LLM). This deployment format optimizes the model for low latency and high throughput inference. - -- [Document Question-Answering with LangChain](../../notebooks/02_langchain_simple.ipynb) - - This notebook demonstrates how to use LangChain to build a chat bot that references a custom knowledge base. LangChain provides a simple framework for connecting LLMs to your own data sources. It shows how to integrate a TensorRT-LLM to LangChain using a custom wrapper. - -- [Document Question-Answering with LlamaIndex](../../notebooks/03_llama_index_simple.ipynb) - - This notebook demonstrates how to use LlamaIndex to build a chat bot that references a custom knowledge base. It contains the same functionality as the preceding notebook, but uses some LlamaIndex components instead of LangChain components. It also shows how the two frameworks can be used together. - -- [Advanced Document Question-Answering with LlamaIndex](../../notebooks/04_llamaindex_hier_node_parser.ipynb) - - This notebook demonstrates how to use LlamaIndex to build a more complex retrieval for a chat bot. The retrieval method shown in this notebook works well for code documentation. The method retrieves more contiguous document blocks that preserve both code snippets and explanations of code. - -- [Upload Press Releases and Interact with REST FastAPI Server](../../notebooks/05_dataloader.ipynb) +- [Upload Press Releases and Interact with REST FastAPI Server](../../notebooks/01_dataloader.ipynb) This notebook demonstrates how to use the REST FastAPI server to upload the knowledge base and then ask a question without and with the knowledge base. -- [NVIDIA AI Endpoint Integration with LangChain](../../notebooks/07_Option(1)_NVIDIA_AI_endpoint_simple.ipynb) +- [NVIDIA AI Endpoint Integration with LangChain](../../notebooks/02_Option(1)_NVIDIA_AI_endpoint_simple.ipynb) This notebook demonstrates how to build a Retrieval Augmented Generation (RAG) example using the NVIDIA AI endpoint integrated with Langchain, with FAISS as the vector store. -- [RAG with LangChain and local LLM model](../../notebooks/07_Option(2)_minimalistic_RAG_with_langchain_local_HF_LLM.ipynb) +- [RAG with LangChain and local LLM model](../../notebooks/02_Option(2)_minimalistic_RAG_with_langchain_local_HF_LLM.ipynb) This notebook demonstrates how to plug in a local LLM from Hugging Face Hub and build a simple RAG app using LangChain. -- [NVIDIA AI Endpoint with LlamaIndex and LangChain](../../notebooks/08_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb) +- [NVIDIA AI Endpoint with LlamaIndex and LangChain](../../notebooks/03_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb) - This notebook demonstrates how to plug in an NVIDIA AI Endpoint mixtral_8x7b and embedding nvolveqa_40k, bind these into LlamaIndex with these customizations. + This notebook demonstrates how to plug in an NVIDIA AI Endpoint ai-mixtral-8x7b-instruct and embedding ai-embed-qa-4, bind these into LlamaIndex with these customizations. -- [Locally deployed model from Hugging Face integration with LlamaIndex and LangChain](../../notebooks/08_Option(2)_llama_index_with_HF_local_LLM.ipynb) +- [Locally deployed model from Hugging Face integration with LlamaIndex and LangChain](../../notebooks/03_Option(2)_llama_index_with_HF_local_LLM.ipynb) This notebook demonstrates how to plug in a local LLM from Hugging Face Hub Llama-2-13b-chat-hf and all-MiniLM-L6-v2 embedding from Hugging Face, bind these to into LlamaIndex with these customizations. -- [LangChain agent with tools plug in multiple models from NVIDIA AI Endpoints](../../notebooks/09_Agent_use_tools_leveraging_NVIDIA_AI_endpoints.ipynb) +- [LangChain agent with tools plug in multiple models from NVIDIA AI Endpoints](../../notebooks/04_Agent_use_tools_leveraging_NVIDIA_AI_endpoints.ipynb) - This notebook demonstrates how to use multiple NVIDIA AI Endpoint models such as mixtral_8x7b, Deplot, and Neva. + This notebook demonstrates how to use multiple NVIDIA AI Endpoint models such as ai-mixtral-8x7b-instruct, Deplot, and Neva. -- [LangChain with HTML documents and NVIDIA AI Endpoints](../../notebooks/10_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb) +- [LangChain with HTML documents and NVIDIA AI Endpoints](../../notebooks/05_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb) This notebook demonstrates how to build a RAG using NVIDIA AI Endpoints for LangChain. The notebook creates a vector store by downloading web pages and generating their embeddings using FAISS. The notebook shows two different chat chains for querying the vector store. -- [LangChain with HTML documents and NVIDIA AI Endpoints](../../notebooks/11_LangGraph_HandlingAgent_IntermediateSteps.ipynb) +- [LangChain with HTML documents and NVIDIA AI Endpoints](../../notebooks/06_LangGraph_HandlingAgent_IntermediateSteps.ipynb) This notebook guides you through creating a basic agent executor using LangGraph. We demonstrate how to handle the logic of the intermediate steps from the agent leveraging different provided tools within langGraph. -- [LangChain with HTML documents and NVIDIA AI Endpoints](../../notebooks/12_Chat_wtih_nvidia_financial_reports.ipynb) +- [LangChain with HTML documents and NVIDIA AI Endpoints](../../notebooks/07_Chat_with_nvidia_financial_reports.ipynb) + + In this notebook, we are going to use milvus as vectorstore, the ai-mixtral-8x7b-instruct as LLM and ai-embed-qa-4 embedding provided by NVIDIA_AI_Endpoint as LLM and embedding model, and build a simply RAG example for chatting with NVIDIA Financial Reports. + +- [RAG with locally deployed models using NIMS](../../notebooks/08_RAG_Langchain_with_Local_NIM.ipynb) - In this notebook, we are going to use milvus as vectorstore, the mixtral_8x7b as LLM and ai-embed-qa-4 embedding provided by NVIDIA_AI_Endpoint as LLM and embedding model, and build a simply RAG example for chatting with NVIDIA Financial Reports. + In this notebook we demonstrate how to build a RAG using [NVIDIA Inference Microservices (NIM)](https://build.nvidia.com/explore/discover). We locally host a `Llama3-8b-instruct` using the NIM LLM container and deploy it using [ NVIDIA AI Endpoints for LangChain](https://python.langchain.com/docs/integrations/chat/nvidia_ai_endpoints/). + In order to run this notebook in a virtual environment, you need to launch the NIM Docker container in the background outside of the notebook environment prior to running the LangChain code in the notebook cells. Run the commands in the first 3 cells from a terminal then begin with the 4th cell (curl inference command) within the notebook environment. ## Running JupyterLab Server Individually diff --git a/docs/llm-inference-server.md b/docs/llm-inference-server.md deleted file mode 100644 index a9298be2f..000000000 --- a/docs/llm-inference-server.md +++ /dev/null @@ -1,61 +0,0 @@ - - -# NeMo Framework Inference Server - -```{contents} ---- -depth: 2 -local: true -backlinks: none ---- -``` - -## About the Inference Server - -The generative AI examples use [NeMo Framework Inference Server](https://docs.nvidia.com/nemo-framework/user-guide/latest/index.html) container. -NeMo can create optimized LLM using TensorRT-LLM and can deploy models using NVIDIA Triton Inference Server for high-performance, cost-effective, and low-latency inference. -Many examples use Llama 2 models and LLM Inference Server container contains modules and scripts that are required for TRT-LLM conversion of the Llama 2 models and deployment using NVIDIA Triton Inference Server. - -The inference server is used with examples that deploy a model on-premises. -The examples that use [NVIDIA AI foundation models](https://www.nvidia.com/en-in/ai-data-science/foundation-models/) or NVIDIA AI Endpoints do not use this component. - - -## Running the Inference Server Individually - -The following steps describe how a Llama 2 model deployment. - -- Download Llama 2 Chat Model Weights from [Meta](https://ai.meta.com/resources/models-and-libraries/llama-downloads/) or [HuggingFace](https://huggingface.co/meta-llama/Llama-2-13b-chat-hf/). You can check [support matrix](support-matrix.md) for GPU requirements for the deployment. - -- Update the `deploy/compose/compose.env` file with `MODEL_DIRECTORY` as the downloaded Llama 2 model path and other model parameters as needed. - -- Build the LLM inference server container from source: - - ```console - $ source deploy/compose/compose.env - $ docker compose -f deploy/compose/rag-app-text-chatbot.yaml build llm - ``` - -- Run the container. The container starts Triton Inference Server with TRT-LLM optimized Llama 2 model: - - ```console - $ source deploy/compose/compose.env - $ docker compose -f deploy/compose/rag-app-text-chatbot.yaml up llm - ``` - -After the optimized Llama 2 model is deployed in Triton Inference Server, clients can send HTTP/REST or gRPC requests directly to the server. -A sample implementation of a client can be found in the `triton_trt_llm.py` file of GitHub repository at [integrations/langchain/llms/](https://github.com/NVIDIA/GenerativeAIExamples/tree/main/integrations/langchain/llms). diff --git a/docs/local-gpu.md b/docs/local-gpu.md deleted file mode 100644 index c620fbacc..000000000 --- a/docs/local-gpu.md +++ /dev/null @@ -1,328 +0,0 @@ - - -# Using Local GPUs for a Q&A Chatbot - -```{contents} ---- -depth: 2 -local: true -backlinks: none ---- -``` - -## Example Features - -This example deploys a developer RAG pipeline for chat Q&A and serves inferencing with the NeMo Framework Inference container. - -This example uses a local host with an NVIDIA A100, H100, or L40S GPU. - -```{list-table} -:header-rows: 1 - -* - Model - - Embedding - - Framework - - Description - - Multi-GPU - - TRT-LLM - - Model Location - - Triton - - Vector Database - -* - llama-2 - - UAE-Large-V1 - - LlamaIndex - - QA chatbot - - NO - - YES - - Local Model - - YES - - Milvus - -* - llama-2 - - UAE-Large-V1 - - LlamaIndex - - QA chatbot - - NO - - YES - - Local Model - - YES - - pgvector -``` - -The following figure shows the sample topology: - -- The sample chat bot web application communicates with the local chain server. - -- The local chain server sends inference requests to NVIDIA Triton Inference Server (TIS). - TIS uses TensorRT-LLM and NVIDIA GPUs with the LLama 2 model for generative AI. - -- The sample chat bot supports uploading documents to create a knowledge base. - The uploaded documents are parsed by the chain server and embeddings are stored - in the vector database, Milvus or pgvector. - When you submit a question and request to use the knowledge base, the chain server - retrieves the most relevant documents and submits them with the question to - TIS to perform retrieval-augumented generation. - -- Optionally, you can deploy NVIDIA Riva. Riva can use automatic speech recognition to - transcribe your questions and use text-to-speech to speak the answers aloud. - -![Sample topology for a RAG pipeline with local GPUs and local inference.](./images/local-gpus-topology.png) - - -## Prerequisites - -- Clone the Generative AI examples Git repository using Git LFS: - - ```console - $ sudo apt -y install git-lfs - $ git clone git@github.com:NVIDIA/GenerativeAIExamples.git - $ cd GenerativeAIExamples/ - $ git lfs pull - ``` - -- A host with an NVIDIA A100, H100, or L40S GPU. - -- Verify NVIDIA GPU driver version 535 or later is installed and that the GPU is in compute mode: - - ```console - $ nvidia-smi -q -d compute - ``` - - *Example Output* - - ```{code-block} output - --- - emphasize-lines: 4,9 - --- - ==============NVSMI LOG============== - - Timestamp : Sun Nov 26 21:17:25 2023 - Driver Version : 535.129.03 - CUDA Version : 12.2 - - Attached GPUs : 1 - GPU 00000000:CA:00.0 - Compute Mode : Default - ``` - - If the driver is not installed or below version 535, refer to the [*NVIDIA Driver Installation Quickstart Guide*](https://docs.nvidia.com/datacenter/tesla/tesla-installation-notes/index.html). - -- Install Docker Engine and Docker Compose. - Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). - -- Install the NVIDIA Container Toolkit. - - 1. Refer to the [installation documentation](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). - - 1. When you configure the runtime, set the NVIDIA runtime as the default: - - ```console - $ sudo nvidia-ctk runtime configure --runtime=docker --set-as-default - ``` - - If you did not set the runtime as the default, you can reconfigure the runtime by running the preceding command. - - 1. Verify the NVIDIA container toolkit is installed and configured as the default container runtime: - - ```console - $ cat /etc/docker/daemon.json - ``` - - *Example Output* - - ```json - { - "default-runtime": "nvidia", - "runtimes": { - "nvidia": { - "args": [], - "path": "nvidia-container-runtime" - } - } - } - ``` - - 1. Run the `nvidia-smi` command in a container to verify the configuration: - - ```console - $ sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi -L - ``` - - *Example Output* - - ```output - GPU 0: NVIDIA A100 80GB PCIe (UUID: GPU-d8ce95c1-12f7-3174-6395-e573163a2ace) - ``` - -- Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - - - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). - - - In the provided `config.sh` script, set `service_enabled_asr=true` and `service_enabled_tts=true`, and select the desired ASR and TTS languages by adding the appropriate language codes to `asr_language_code` and `tts_language_code`. - - - After the server is running, assign its IP address (or hostname) and port (50051 by default) to `RIVA_API_URI` in `deploy/compose/compose.env`. - - - Alternatively, you can use a hosted Riva API endpoint. You might need to obtain an API key and/or Function ID for access. - - In `deploy/compose/compose.env`, make the following assignments as necessary: - - ```bash - export RIVA_API_URI=":" - export RIVA_API_KEY="" - export RIVA_FUNCTION_ID="" - ``` - -## Download the Llama 2 Model and Weights - -1. Fill out Meta's [Llama request access form](https://ai.meta.com/resources/models-and-libraries/llama-downloads/). - - - Select the **Llama 2 & Llama Chat** checkbox. - - After verifying your email, Meta will email you a download link. - -1. Clone the Llama repository: - - ```console - $ git clone https://github.com/facebookresearch/llama.git - $ cd llama/ - ``` - -1. Run the `download.sh` script. When prompted, specify `13B-chat` to download the llama-2-13b-chat model: - - ```console - $ ./download.sh - Enter the URL from email: < https://download.llamameta.net/...> - - Enter the list of models to download without spaces (7B,13B,70B,7B-chat,13B-chat,70B-chat), or press Enter for all: 13B-chat - ``` - -1. Copy the tokenizer to the model directory. - - ```console - $ mv tokenizer* llama-2-13b-chat/ - $ ls llama-2-13b-chat/ - ``` - - *Example Output* - - ```output - checklist.chk consolidated.00.pth consolidated.01.pth params.json tokenizer.model tokenizer_checklist.chk - ``` - -## Build and Start the Containers - -1. In the Generative AI Examples repository, edit the `deploy/compose/compose.env` file. - - Specify the absolute path to the model location, model architecture, and model name. - - ```bash - # full path to the local copy of the model weights - # NOTE: This should be an absolute path and not relative path - export MODEL_DIRECTORY="/path/to/llama/llama-2-13b_chat/" - - # the architecture of the model. eg: llama - export MODEL_ARCHITECTURE="llama" - - # the name of the model being used - only for displaying on frontend - export MODEL_NAME="Llama-2-13b-chat" - ... - ``` - -1. From the root of the repository, build the containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml build - ``` - -1. Start the containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml up -d - ``` - - NVIDIA Triton Inference Server can require 5 minutes to start. The `-d` flag starts the services in the background. - - *Example Output* - - ```output - ✔ Network nvidia-rag Created - ✔ Container notebook-server Started - ✔ Container llm-inference-server Started - ✔ Container chain-server Started - ✔ Container rag-playground Started - ``` - -1. Start the Milvus vector database: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus - ``` - - *Example Output* - - ```output - ✔ Container milvus-minio Started - ✔ Container milvus-etcd Started - ✔ Container milvus-standalone Started - ``` - -1. Confirm the containers are running: - - ```console - $ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}" - ``` - - *Example Output* - - ```output - CONTAINER ID NAMES STATUS - 256da0ecdb7b rag-playground Up 48 minutes - 2974aa4fb2ce chain-server Up 48 minutes - 4a8c4aebe4ad notebook-server Up 48 minutes - 5be2b57bb5c1 milvus-standalone Up 48 minutes (healthy) - ecf674c8139c llm-inference-server Up 48 minutes (healthy) - a6609c22c171 milvus-minio Up 48 minutes (healthy) - b23c0858c4d4 milvus-etcd Up 48 minutes (healthy) - ``` - - -### Related Information - -- [Meta Llama README](https://github.com/facebookresearch/llama/blob/main/README.md) -- [Meta Llama request access form](https://ai.meta.com/resources/models-and-libraries/llama-downloads/) - - -## Stopping the Containers - -1. Stop the vector database: - - ```console - $ docker compose -f deploy/compose/docker-compose-vectordb.yaml down - ``` - -1. Stop and remove the application containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml down - ``` - -## Next Steps - -- Use the [](./using-sample-web-application.md). -- [](./vector-database.md) -- Run the sample Jupyter notebooks to learn about optional features. diff --git a/docs/multi-gpu.md b/docs/multi-gpu.md deleted file mode 100644 index 19cd390f2..000000000 --- a/docs/multi-gpu.md +++ /dev/null @@ -1,404 +0,0 @@ - - -# Multi-GPU for Inference - -```{contents} ---- -depth: 2 -local: true -backlinks: none ---- -``` - -## Comparison with the Local GPUs Example - -This example is very similar to the example that uses local GPUs. -The key difference is to modify the `deploy/compose/rag-app-text-chatbot.yaml` file to specify the GPU device IDs for the services. -If you performed all the steps in [](local-gpu.md), consider skipping to -step 1 of [](#build-and-start-the-containers) on this page. - - -## Special Considerations for Tensor Parallelism - -When you use more than two GPUs for the inference server, you might need to specify additional command-line arguments. - -The special consideration is that the attention head size for the model must be a multiple of the tensor parallelism size. -For the Llama-2-13B chat model, the model attention head size is 40. -You can view this value in the `n_heads: 40` field in the `llama-2-13b-chat/params.json` file after you download the model or from the Hugging Face Model Hub: . - -The tensor parallelism is calculated as {math}`\mbox{tensor-parallelism} = \mbox{world-size} \div \mbox{pipeline-parallelism}` -where $\mbox{world-size}$ is the number of GPUs and $\mbox{pipeline-parallelism}$ has a default value of 1. - -With 1, 2, 4, 5, or any number of GPUs that divide 40 into equally, no action is required. - -For 3, 6, or any other number that does not divide equally into 40, you can specify a pipeline parallelism value so that the tensor parallelism is a whole number. -For example, to use 6 GPUs, you can specify `--pipeline-parallelism 3` on the inference server command line so that tensor parallelism is 2. - -If you use a different model, refer to the `params.json` file. -For example, the Llama-2-7B chat model has `n_heads: 32` and the Llama-2-70B chat model has `n_heads: 64`. - - -## Example Features - -This example deploys a developer RAG pipeline for chat Q&A and serves inferencing with the NeMo Framework Inference container across multiple local GPUs. - -This example uses a local host with an NVIDIA A100, H100, or L40S GPU. - -```{list-table} -:header-rows: 1 - -* - Model - - Embedding - - Framework - - Description - - Multi-GPU - - TRT-LLM - - Model Location - - Triton - - Vector Database - -* - llama-2 - - UAE-Large-V1 - - LlamaIndex - - QA chatbot - - YES - - YES - - Local Model - - YES - - Milvus - -* - llama-2 - - UAE-Large-V1 - - LlamaIndex - - QA chatbot - - YES - - YES - - Local Model - - YES - - pgvector -``` - -The following figure shows the sample topology: - -- The sample chat bot web application communicates with the local chain server. - -- The chain server sends inference requests to NVIDIA Triton Inference Server (TIS). - TIS uses TensorRT-LLM and NVIDIA GPUs with the LLama 2 model for generative AI. - -- The sample chat bot supports uploading documents to create a knowledge base. - The uploaded documents are parsed by the chain server and embeddings are stored - in the vector database, Milvus or pgvector. - When you submit a question and request to use the knowledge base, the chain server - retrieves the most relevant documents and submits them with the question to - TIS to perform retrieval-augumented generation. - -- Optionally, you can deploy NVIDIA Riva. Riva can use automatic speech recognition to - transcribe your questions and use text-to-speech to speak the answers aloud. - -![Sample topology for a RAG pipeline with local GPUs and local inference.](./images/local-gpus-topology.png) - - -## Prerequisites - -- Clone the Generative AI examples Git repository using Git LFS: - - ```console - $ sudo apt -y install git-lfs - $ git clone git@github.com:NVIDIA/GenerativeAIExamples.git - $ cd GenerativeAIExamples/ - $ git lfs pull - ``` - -- A host with one or more NVIDIA A100, H100, or L40S GPU. - -- Verify NVIDIA GPU driver version 535 or later is installed and that the GPU is in compute mode: - - ```console - $ nvidia-smi -q -d compute - ``` - - *Example Output* - - ```{code-block} output - --- - emphasize-lines: 4,9 - --- - ==============NVSMI LOG============== - - Timestamp : Sun Nov 26 21:17:25 2023 - Driver Version : 535.129.03 - CUDA Version : 12.2 - - Attached GPUs : 2 - GPU 00000000:CA:00.0 - Compute Mode : Default - - GPU 00000000:FA:00.0 - Compute Mode : Default - ``` - - If the driver is not installed or below version 535, refer to the [*NVIDIA Driver Installation Quickstart Guide*](https://docs.nvidia.com/datacenter/tesla/tesla-installation-notes/index.html). - -- Install Docker Engine and Docker Compose. - Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). - -- Install the NVIDIA Container Toolkit. - - 1. Refer to the [installation documentation](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). - - 1. When you configure the runtime, set the NVIDIA runtime as the default: - - ```console - $ sudo nvidia-ctk runtime configure --runtime=docker --set-as-default - ``` - - If you did not set the runtime as the default, you can reconfigure the runtime by running the preceding command. - - 1. Verify the NVIDIA container toolkit is installed and configured as the default container runtime: - - ```console - $ cat /etc/docker/daemon.json - ``` - - *Example Output* - - ```json - { - "default-runtime": "nvidia", - "runtimes": { - "nvidia": { - "args": [], - "path": "nvidia-container-runtime" - } - } - } - ``` - - 1. Run the `nvidia-smi` command in a container to verify the configuration: - - ```console - $ sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi -L - ``` - - *Example Output* - - ```output - GPU 0: NVIDIA A100 80GB PCIe (UUID: GPU-d8ce95c1-12f7-3174-6395-e573163a2ace) - GPU 1: NVIDIA A100 80GB PCIe (UUID: GPU-1d37ef30-0861-de64-a06d-73257e247a0d) - ``` - -- Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - - - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). - - - In the provided `config.sh` script, set `service_enabled_asr=true` and `service_enabled_tts=true`, and select the desired ASR and TTS languages by adding the appropriate language codes to `asr_language_code` and `tts_language_code`. - - - After the server is running, assign its IP address (or hostname) and port (50051 by default) to `RIVA_API_URI` in `deploy/compose/compose.env`. - - - Alternatively, you can use a hosted Riva API endpoint. You might need to obtain an API key and/or Function ID for access. - - In `deploy/compose/compose.env`, make the following assignments as necessary: - - ```bash - export RIVA_API_URI=":" - export RIVA_API_KEY="" - export RIVA_FUNCTION_ID="" - ``` - -## Download the Llama 2 Model and Weights - -1. Fill out Meta's [Llama request access form](https://ai.meta.com/resources/models-and-libraries/llama-downloads/). - - - Select the **Llama 2 & Llama Chat** checkbox. - - After verifying your email, Meta will email you a download link. - -1. Clone the Llama repository: - - ```console - $ git clone https://github.com/facebookresearch/llama.git - $ cd llama/ - ``` - -1. Run the `download.sh` script. When prompted, specify `13B-chat` to download the llama-2-13b-chat model: - - ```console - $ ./download.sh - Enter the URL from email: < https://download.llamameta.net/...> - - Enter the list of models to download without spaces (7B,13B,70B,7B-chat,13B-chat,70B-chat), or press Enter for all: 13B-chat - ``` - -1. Copy the tokenizer to the model directory. - - ```console - $ mv tokenizer* llama-2-13b-chat/ - $ ls llama-2-13b-chat/ - ``` - - *Example Output* - - ```output - checklist.chk consolidated.00.pth consolidated.01.pth params.json tokenizer.model tokenizer_checklist.chk - ``` - -## Build and Start the Containers - -1. In the Generative AI Examples repository, edit the `deploy/compose/rag-app-text-chatbot.yaml` file. - - Specify the GPU device IDs to assign to the services. - Refer to [](#special-considerations-for-tensor-parallelism) when specifying more than two GPUs. - - ```yaml - services: - llm: - // ... - command: # Add --pipeline-parallelism if you need to specify a value. - deploy: - resources: - reservations: - devices: - - driver: nvidia - # count: ${INFERENCE_GPU_COUNT:-all} # Comment this out - device_ids: ["0", "1"] - capabilities: [gpu] - - jupyter-server: - // ... - deploy: - resources: - reservations: - devices: - - driver: nvidia - # count: 1 # Comment this out - device_ids: ["2"] - capabilities: [gpu] - ``` - -1. Edit the `deploy/compose/docker-compose-vectordb.yaml` file. - - Specify the GPU device IDs to assign to the services: - - ```yaml - services: - milvus: - // ... - deploy: - resources: - reservations: - devices: - - driver: nvidia - # count: 1 # Comment this out - device_ids: ["3"] - capabilities: [gpu] - ``` - - You can share device IDs between vector database and Jupyter Server. - -1. Edit the `deploy/compose/compose.env` file. - - Specify the absolute path to the model location, model architecture, and model name. - - ```bash - # full path to the local copy of the model weights - # NOTE: This should be an absolute path and not relative path - export MODEL_DIRECTORY="/path/to/llama/llama-2-13b_chat/" - - # the architecture of the model. eg: llama - export MODEL_ARCHITECTURE="llama" - - # the name of the model being used - only for displaying on frontend - export MODEL_NAME="Llama-2-13b-chat" - ... - ``` - -1. From the root of the repository, build the containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml build - ``` - -1. Start the containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml up -d - ``` - - NVIDIA Triton Inference Server can require 5 minutes to start. The `-d` flag starts the services in the background. - - *Example Output* - - ```output - ✔ Network nvidia-rag Created - ✔ Container llm-inference-server Started - ✔ Container notebook-server Started - ✔ Container chain-server Started - ✔ Container rag-playground Started - ``` - -1. Start the Milvus vector database: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus - ``` - - *Example Output* - - ```output - ✔ Container milvus-minio Started - ✔ Container milvus-etcd Started - ✔ Container milvus-standalone Started - ``` - -1. Confirm the containers are running: - - ```console - $ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}" - ``` - - *Example Output* - - ```output - CONTAINER ID NAMES STATUS - 256da0ecdb7b rag-playground Up 48 minutes - 2974aa4fb2ce chain-server Up 48 minutes - 4a8c4aebe4ad notebook-server Up 48 minutes - 5be2b57bb5c1 milvus-standalone Up 48 minutes (healthy) - ecf674c8139c llm-inference-server Up 48 minutes (healthy) - a6609c22c171 milvus-minio Up 48 minutes (healthy) - b23c0858c4d4 milvus-etcd Up 48 minutes (healthy) - ``` - -### Related Information - -- [Meta Llama README](https://github.com/facebookresearch/llama/blob/main/README.md) -- [Meta Llama request access form](https://ai.meta.com/resources/models-and-libraries/llama-downloads/) - - -## Stopping the Containers - -- To uninstall, stop and remove the running containers from the root of the Generative AI Examples repository: - - ```console - $ docker compose -f deploy/compose/rag-app-text-chatbot.yaml down - ``` - -## Next Steps - -- Use the [](./using-sample-web-application.md). -- [](./vector-database.md) -- Run the sample Jupyter notebooks to learn about optional features. diff --git a/docs/multi-turn.md b/docs/multi-turn.md index a7592c3b5..bd1a7738b 100644 --- a/docs/multi-turn.md +++ b/docs/multi-turn.md @@ -53,11 +53,11 @@ This example uses models from the NVIDIA API Catalog. - Multi-GPU - TRT-LLM - Model Location - - Triton + - NIM for LLMs - Vector Database -* - ai-llama2-70b - - ai-embed-qa-4 +* - meta/llama3-8b-instruct + - snowflake-arctic-embed-l - LangChain - QA chatbot - NO @@ -90,6 +90,14 @@ The following figure shows the sample topology: - Install Docker Engine and Docker Compose. Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). +- Login to Nvidia's docker registry. Please refer to [instructions](https://docs.nvidia.com/ngc/gpu-cloud/ngc-overview/index.html) to create account and generate NGC API key. This is needed for pulling in the secure base container used by all the examples. + + ```console + $ docker login nvcr.io + Username: $oauthtoken + Password: + ``` + - Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). @@ -108,9 +116,9 @@ The following figure shows the sample topology: export RIVA_FUNCTION_ID="" ``` -## Get an API Key for the Llama 2 70B API Endpoint +## Get an API Key for the Llama 3 8B API Endpoint -```{include} query-decomposition.md +```{include} multimodal-data.md :start-after: api-key-start :end-before: api-key-end ``` @@ -148,7 +156,11 @@ The following figure shows the sample topology: 1. Start the Milvus vector database: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-vectordb.yaml \ + --profile llm-embedding \ + up -d milvus ``` *Example Output* @@ -184,4 +196,4 @@ The following figure shows the sample topology: - Enable the **Use knowledge base** checkbox when you submit a question. - [](./vector-database.md) - Stop the containers by running `docker compose -f deploy/compose/rag-app-multiturn-chatbot.yaml down` and - `docker compose -f deploy/compose/docker-compose-vectordb.yaml down`. + `docker compose -f deploy/compose/docker-compose-vectordb.yaml --profile llm-embedding down`. diff --git a/docs/multimodal-data.md b/docs/multimodal-data.md index 32eabcd8c..0215d234c 100644 --- a/docs/multimodal-data.md +++ b/docs/multimodal-data.md @@ -28,12 +28,12 @@ backlinks: none ## Example Features This example deploys a developer RAG pipeline for chat Q&A and serves inferencing from NVIDIA API Catalog endpoints -instead of NVIDIA Triton Inference Server, a local Llama 2 model, or local GPUs. +instead of a local inference server, a local LLM, or local GPUs. Developers get free credits for 10K requests to any of the available models. The key difference from the [](./api-catalog.md) example is that this example demonstrates how work with multimodal data. -The model works with any kind of image in PDF, such as graphs and plots, as well as text and tables. +The model works with any kind of image in PDF or PPTX, such as graphs and plots, as well as text and tables. This example uses models from the NVIDIA API Catalog. @@ -48,15 +48,15 @@ This example uses models from the NVIDIA API Catalog. - Multi-GPU - TRT-LLM - Model Location - - Triton + - NIM for LLMs - Vector Database -* - ai-mixtral-8x7b-instruct for response generation +* - meta/llama3-8b-instruct for response generation ai-google-Deplot for graph to text conversion ai-Neva-22B for image to text conversion - - ai-embed-qa-4 + - snowflake-arctic-embed-l - Custom Python - QA chatbot - NO @@ -79,7 +79,7 @@ The following figure shows the sample topology: ## Limitations Although the AI Foundation Models endpoint uses the Neva_22B model for processing images, this example -supports uploading images that are part of PDF files only. +supports uploading images that are part of PDF and PPTX files only. For example, after deploying the services, you cannot upload a PNG, JPEG, TIFF, or any other image format file. @@ -97,6 +97,14 @@ For example, after deploying the services, you cannot upload a PNG, JPEG, TIFF, - Install Docker Engine and Docker Compose. Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). +- Login to Nvidia's docker registry. Please refer to [instructions](https://docs.nvidia.com/ngc/gpu-cloud/ngc-overview/index.html) to create account and generate NGC API key. This is needed for pulling in the secure base container used by all the examples. + + ```console + $ docker login nvcr.io + Username: $oauthtoken + Password: + ``` + - Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). @@ -115,12 +123,33 @@ For example, after deploying the services, you cannot upload a PNG, JPEG, TIFF, export RIVA_FUNCTION_ID="" ``` -## Get an API Key for the Mixtral 8x7B Instruct API Endpoint +## Get an API Key for the Meta Llama 3 8B Instruct API Endpoint -```{include} api-catalog.md -:start-after: api-key-start -:end-before: api-key-end -``` +% api-key-start + +Perform the following steps if you do not already have an API key. +You can use different model API endpoints with the same API key. + +1. Navigate to . + +2. Find the **Llama 3 8B Instruct** card and click the card. + + ![Llama 3 8B Instruct model card](./images/llama3-8b-instruct-model-card.png) + +3. Click **Get API Key**. + + ![API section of the model page.](./images/llama3-8b-instruct-get-api-key.png) + +4. Click **Generate Key**. + + ![Generate key window.](./images/api-catalog-generate-api-key.png) + +5. Click **Copy Key** and then save the API key. + The key begins with the letters nvapi-. + + ![Key Generated window.](./images/key-generated.png) + +% api-key-end ## Build and Start the Containers @@ -155,7 +184,11 @@ For example, after deploying the services, you cannot upload a PNG, JPEG, TIFF, 1. Start the Milvus vector database: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-vectordb.yaml \ + --profile llm-embedding \ + up -d milvus ``` *Example Output* @@ -187,7 +220,7 @@ For example, after deploying the services, you cannot upload a PNG, JPEG, TIFF, - Access the web interface for the chat server. Refer to [](./using-sample-web-application.md) for information about using the web interface. -- Upload one or more PDF files with graphics, plots, and tables. +- Upload one or more PDF and PPTX files with graphics, plots, and tables. - Enable the **Use knowledge base** checkbox when you submit a question. - Stop the containers by running `docker compose -f deploy/compose/rag-app-multimodal-chatbot.yaml down` and - `docker compose -f deploy/compose/docker-compose-vectordb.yaml down`. + `docker compose -f deploy/compose/docker-compose-vectordb.yaml --profile llm-embedding down`. diff --git a/docs/nim-llms.md b/docs/nim-llms.md index ed06c756a..cf3d2d94e 100644 --- a/docs/nim-llms.md +++ b/docs/nim-llms.md @@ -31,6 +31,15 @@ NVIDIA NIM for LLMs provides the enterprise-ready approach for deploying large l If you are approved for [early access to NVIDIA NeMo Microservices](https://developer.nvidia.com/nemo-microservices), you can run the examples with NIM for LLMs. +The following figure shows the sample topology: + +- The sample chat bot web application communicates with the chain server. + The chain server sends inference requests to a local NVIDIA NIM for LLMs microservice. +- Optionally, you can deploy NVIDIA Riva. Riva can use automatic speech recognition to transcribe + your questions and use text-to-speech to speak the answers aloud. + +![Using NVIDIA NIM for LLMs.](./images/nim-llms-topology.png) + ## Prerequisites @@ -137,41 +146,39 @@ If you are approved for [early access to NVIDIA NeMo Microservices](https://deve ``` -## Deploy NIM for LLMs and NeMo Retriever Embedding - -- Deploy an LLM with NIM for LLMs, such as Llama-2-13b-chat-hf or Mixtral 8x7b Instruct. - Refer to the [Llama 2 70B Chat](https://docs.nvidia.com/ai-enterprise/nim-llm/latest/quickstart/llama2-70b-chat.html) quick start, or another quick start in the _NVIDIA NIM for LLMs_ documentation. +## Build and Start the Containers -- Deploy a text embedding model, such as NV-Embed-QA. - Refer to [Deploying Text Embedding Models](https://developer.nvidia.com/docs/nemo-microservices/embedding/source/deploy.html) - in the _NVIDIA NeMo Retriever Embedding_ documentation. - - -## Build and Start the Chain Server and RAG Playground +1. Create a `model-cache` directory to download and store the models + ```bash + mkdir -p model-cache + ``` 1. In the Generative AI Examples repository, edit the `deploy/compose/compose.env` file. - Add the following environment variables. + Add or update the following environment variables. ```bash - # Name of the deployed LLM model. - export APP_LLM_MODELNAME= - - export APP_LLM_MODELENGINE=nvidia-ai-endpoints + # full path to the `model-cache` directory + # NOTE: This should be an absolute path and not relative path + export MODEL_DIRECTORY="/path/to/model/cache/directory/" # IP of system where llm is deployed. - export APP_LLM_SERVERURL=":" + export APP_LLM_SERVERURL="nemollm-inference:8000" # Name of the deployed embedding model (NV-Embed-QA) - export APP_EMBEDDINGS_MODELNAME= + export APP_EMBEDDINGS_MODELNAME="NV-Embed-QA" export APP_EMBEDDINGS_MODELENGINE=nvidia-ai-endpoints + # IP of system where embedding model is deployed. - export APP_EMBEDDINGS_SERVERURL=":" + export APP_EMBEDDINGS_SERVERURL="nemollm-embedding:9080" # Or ranking-ms:8080 for the reranking example. + + # GPU for use by Milvus + export VECTORSTORE_GPU_DEVICE_ID= ... ``` -1. From the root of the repository, build the containers: +1. Build the Chain Server and RAG Playground containers: ```console $ docker compose \ @@ -180,20 +187,10 @@ If you are approved for [early access to NVIDIA NeMo Microservices](https://deve build chain-server rag-playground ``` + Avoid GPU memory errors by assigning a GPU to the Chain Server. + Update `device_ids` in the `chain-server` service of `deploy/compose/rag-app-text-chatbot.yaml` manifest to specify a unique GPU ID. You can specify a different Docker Compose file, such as `deploy/compose/rag-app-multiturn-chatbot.yaml`. -1. Start the Chain Server and RAG Playground: - - ```console - $ docker compose \ - --env-file deploy/compose/compose.env \ - -f deploy/compose/rag-app-text-chatbot.yaml \ - up -d --no-deps chain-server rag-playground - ``` - - The `-d` argument starts the services in the background and the `--no-deps` argument avoids starting a second inference server. - - `Note`: To avoid memory issues, deploy the chain server on a separate GPU from the LLM. Update `device_ids` in `chain-server` service of `deploy/compose/rag-app-text-chatbot.yaml` (or relevant Docker Compose file) to specify a different GPU ```yaml deploy: resources: @@ -204,14 +201,45 @@ If you are approved for [early access to NVIDIA NeMo Microservices](https://deve capabilities: [gpu] ``` -1. Start the Milvus vector database: +1. Start the Chain Server and RAG Playground: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/rag-app-text-chatbot.yaml \ + up -d --no-deps chain-server rag-playground ``` - `Note`: To avoid memory issues, deploy the milvus on a separate GPU from the LLM. Update `VECTORSTORE_GPU_DEVICE_ID` in `deploy/compose/compose.env` + + The `-d` argument starts the services in the background and the `--no-deps` argument avoids starting the JupyterLab server. + +1. Start the NIM for LLMs and NeMo Embedding Microservices containers. + + 1. Export the `NGC_API_KEY` environment variable that the containers use to download models from NVIDIA NGC: + + ```console + export NGC_API_KEY=M2... + ``` + + The NGC API key has a different value than the NVIDIA API key that the API catalog examples use. + + 1. Start the containers: + + ```console + $ DOCKER_USER=$(id -u) docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-nim-ms.yaml \ + --profile llm-embedding \ + up -d + ``` + +1. Start the Milvus vector database: + ```console - export VECTORSTORE_GPU_DEVICE_ID= + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-vectordb.yaml \ + --profile llm-embedding \ + up -d milvus ``` 1. Confirm the containers are running: @@ -239,7 +267,17 @@ If you are approved for [early access to NVIDIA NeMo Microservices](https://deve 1. Stop the vector database: ```console - $ docker compose -f deploy/compose/docker-compose-vectordb.yaml down + $ docker compose -f deploy/compose/docker-compose-vectordb.yaml --profile llm-embedding down + ``` + +1. Stop the NIM for LLMs and NeMo Retriever Embedding Microservices: + + ```console + $ DOCKER_USER=$(id -u) docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-nim-ms.yaml \ + --profile llm-embedding \ + down ``` 1. Stop and remove the application containers: @@ -251,7 +289,17 @@ If you are approved for [early access to NVIDIA NeMo Microservices](https://deve 1. Stop the NIM for LLMs container and NeMo Retriever Embedding container by pressing Ctrl+C in each terminal. +## Related Information + +- [_NVIDIA NIM for LLMs_](https://docs.nvidia.com/nim/large-language-models/latest/index.html) + +- [_NVIDIA NeMo Retriever Embedding_](https://developer.nvidia.com/docs/nemo-microservices/embedding/source/overview.html) + +- [_NVIDIA NeMo Retriever Reranking_](https://developer.nvidia.com/docs/nemo-microservices/reranking/source/overview.html) + + ## Next Steps - Use the [](./using-sample-web-application.md). - [](./vector-database.md) + diff --git a/docs/project.json b/docs/project.json index 4939983c8..fa9aa38b4 100644 --- a/docs/project.json +++ b/docs/project.json @@ -1 +1 @@ -{"name": "generative-ai-examples", "version": "0.5.0"} \ No newline at end of file +{"name": "generative-ai-examples", "version": "0.7.0"} \ No newline at end of file diff --git a/docs/quantized-llm-model.md b/docs/quantized-llm-model.md deleted file mode 100644 index 7b76d6b70..000000000 --- a/docs/quantized-llm-model.md +++ /dev/null @@ -1,349 +0,0 @@ - - -# Quantized LLM Inference Model - -```{contents} ---- -depth: 2 -local: true -backlinks: none ---- -``` - - -## Example Features - -This example deploys a developer RAG pipeline for chat Q&A and serves inferencing with the NeMo Framework Inference container across multiple local GPUs with a -quantized version of the Llama 7B chat model. - -This example uses a local host with an NVIDIA A100, H100, or L40S GPU. - -```{list-table} -:header-rows: 1 - -* - Model - - Embedding - - Framework - - Description - - Multi-GPU - - TRT-LLM - - Model Location - - Triton - - Vector Database - -* - llama-2-7b-chat - - UAE-Large-V1 - - LlamaIndex - - QA chatbot - - YES - - YES - - Local Model - - YES - - Milvus -``` - -## Prerequisites - -- Clone the Generative AI examples Git repository using Git LFS: - - ```console - $ sudo apt -y install git-lfs - $ git clone git@github.com:NVIDIA/GenerativeAIExamples.git - $ cd GenerativeAIExamples/ - $ git lfs pull - ``` - -- A host with one or more NVIDIA A100, H100, or L40S GPU. - -- Verify NVIDIA GPU driver version 535 or later is installed and that the GPU is in compute mode: - - ```console - $ nvidia-smi -q -d compute - ``` - - *Example Output* - - ```{code-block} output - --- - emphasize-lines: 4,9 - --- - ==============NVSMI LOG============== - - Timestamp : Sun Nov 26 21:17:25 2023 - Driver Version : 535.129.03 - CUDA Version : 12.2 - - Attached GPUs : 2 - GPU 00000000:CA:00.0 - Compute Mode : Default - - GPU 00000000:FA:00.0 - Compute Mode : Default - ``` - - If the driver is not installed or below version 535, refer to the [*NVIDIA Driver Installation Quickstart Guide*](https://docs.nvidia.com/datacenter/tesla/tesla-installation-notes/index.html). - -- Install Docker Engine and Docker Compose. - Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). - -- Install the NVIDIA Container Toolkit. - - 1. Refer to the [installation documentation](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). - - 1. When you configure the runtime, set the NVIDIA runtime as the default: - - ```console - $ sudo nvidia-ctk runtime configure --runtime=docker --set-as-default - ``` - - If you did not set the runtime as the default, you can reconfigure the runtime by running the preceding command. - - 1. Verify the NVIDIA container toolkit is installed and configured as the default container runtime: - - ```console - $ cat /etc/docker/daemon.json - ``` - - *Example Output* - - ```json - { - "default-runtime": "nvidia", - "runtimes": { - "nvidia": { - "args": [], - "path": "nvidia-container-runtime" - } - } - } - ``` - - 1. Run the `nvidia-smi` command in a container to verify the configuration: - - ```console - $ sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi -L - ``` - - *Example Output* - - ```output - GPU 0: NVIDIA A100 80GB PCIe (UUID: GPU-d8ce95c1-12f7-3174-6395-e573163a2ace) - GPU 1: NVIDIA A100 80GB PCIe (UUID: GPU-1d37ef30-0861-de64-a06d-73257e247a0d) - ``` - -- Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - - - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). - - - In the provided `config.sh` script, set `service_enabled_asr=true` and `service_enabled_tts=true`, and select the desired ASR and TTS languages by adding the appropriate language codes to `asr_language_code` and `tts_language_code`. - - - After the server is running, assign its IP address (or hostname) and port (50051 by default) to `RIVA_API_URI` in `deploy/compose/compose.env`. - - - Alternatively, you can use a hosted Riva API endpoint. You might need to obtain an API key and/or Function ID for access. - - In `deploy/compose/compose.env`, make the following assignments as necessary: - - ```bash - export RIVA_API_URI=":" - export RIVA_API_KEY="" - export RIVA_FUNCTION_ID="" - ``` - -## Download the Llama 2 Model and Weights - -1. Go to . - - - Locate the model to download, such as [Llama 2 7B chat HF](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf). - - Follow the information about accepting the license terms from Meta. - - Log in or sign up for an account with Hugging Face. - -1. After you are granted access, clone the repository by clicking the vertical ellipses button and selecting **Clone repository**. - - During the clone, you might be asked for your username and password multiple times. - Provide the information until the clone is complete. - - -## Download TensorRT-LLM and Quantize the Model - -The following steps summarize downloading the TensorRT-LLM repository, -building a container image, and quantizing the model. - -1. Clone the NVIDIA TensorRT-LLM repository: - - ```console - $ git clone https://github.com/NVIDIA/TensorRT-LLM.git - $ cd TensorRT-LLM - $ git checkout release/0.5.0 - $ git submodule update --init --recursive - $ git lfs install - $ git lfs pull - ``` - -1. Build the TensorRT-LLM Docker image: - - ```console - $ make -C docker release_build - ``` - - Building the image can require more than 30 minutes and requires approximately 30 GB. - The image is named tensorrt_llm/release:latest. - -1. Start the container. - Ensure that the container has one volume mount to the model directory and one volume mount to the TensorRT-LLM repository: - - ```console - $ docker run --rm -it --gpus all --ipc=host \ - -v :/model-store \ - -v $(pwd):/repo -w /repo \ - --ulimit memlock=-1 --shm-size=20g \ - tensorrt_llm/release:latest bash - ``` - -1. Install NVIDIA AMMO Toolkit in the container: - - ```console - # Obtain the cuda version from the system. Assuming nvcc is available in path. - $ cuda_version=$(nvcc --version | grep 'release' | awk '{print $6}' | awk -F'[V.]' '{print $2$3}') - # Obtain the python version from the system. - $ python_version=$(python3 --version 2>&1 | awk '{print $2}' | awk -F. '{print $1$2}') - # Download and install the AMMO package from the DevZone. - $ wget https://developer.nvidia.com/downloads/assets/cuda/files/nvidia-ammo/nvidia_ammo-0.3.0.tar.gz - $ tar -xzf nvidia_ammo-0.3.0.tar.gz - $ pip install nvidia_ammo-0.3.0/nvidia_ammo-0.3.0+cu$cuda_version-cp$python_version-cp$python_version-linux_x86_64.whl - # Install the additional requirements - $ pip install -r examples/quantization/requirements.txt - ``` - -1. Install version `0.25.0` of the accelerate Python package: - - ```console - $ pip install accelerate==0.25.0 - ``` - -1. Run the quantization with the container: - - ```console - $ python3 examples/llama/quantize.py --model_dir /model-store \ - --dtype float16 --qformat int4_awq \ - --export_path ./llama-2-7b-4bit-gs128-awq.pt --calib_size 32 - ``` - - Quantization can require more than 15 minutes to complete. - The sample command creates a `llama-2-7b-4bit-gs128-awq.pt` - quantized checkpoint. - -1. Copy the quantized checkpoint directory to the model directory: - - ```console - $ cp .pt - ``` - -The preceding steps summarize several documents from the NVIDIA TensorRT-LLM GitHub repository. -Refer to the repository for more detail about the following topics: - -- Building the TensorRT-LLM image, refer to the [installation.md](https://github.com/NVIDIA/TensorRT-LLM/blob/release/0.5.0/docs/source/installation.md) file in the release/0.5.0 branch. - -- Installing NVIDIA AMMO Toolkit, refer to the [README](https://github.com/NVIDIA/TensorRT-LLM/blob/release/0.5.0/examples/quantization/README.md) file in the `examples/quantization` directory. - -- Running the `quantize.py` command, refer to [AWQ](https://github.com/NVIDIA/TensorRT-LLM/blob/release/0.5.0/examples/llama/README.md#awq) in the `examples/llama` directory. - - -## Build and Start the Containers - -1. In the Generative AI Examples repository, edit the `deploy/compose/compose.env` file. - - - Update the `MODEL_DIRECTORY` variable to identify the Llama 2 model directory that contains the quantized checkpoint. - - - Uncomment the `QUANTIZATION` variable: - - ```text - export QUANTIZATION="int4_awq" - ``` - -1. From the root of the repository, build the containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml build - ``` - -1. Start the containers: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml up -d - ``` - - NVIDIA Triton Inference Server can require 5 minutes to start. The `-d` flag starts the services in the background. - - *Example Output* - - ```output - ✔ Network nvidia-rag Created - ✔ Container llm-inference-server Started - ✔ Container notebook-server Started - ✔ Container chain-server Started - ✔ Container rag-playground Started - ``` - -1. Start the Milvus vector database: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus - ``` - - *Example Output* - - ```output - ✔ Container milvus-minio Started - ✔ Container milvus-etcd Started - ✔ Container milvus-standalone Started - ``` - -1. Confirm the containers are running: - - ```console - $ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}" - ``` - - *Example Output* - - ```output - CONTAINER ID NAMES STATUS - 256da0ecdb7b rag-playground Up 48 minutes - 2974aa4fb2ce chain-server Up 48 minutes - 4a8c4aebe4ad notebook-server Up 48 minutes - 5be2b57bb5c1 milvus-standalone Up 48 minutes (healthy) - ecf674c8139c llm-inference-server Up 48 minutes (healthy) - a6609c22c171 milvus-minio Up 48 minutes (healthy) - b23c0858c4d4 milvus-etcd Up 48 minutes (healthy) - ``` - -## Stopping the Containers - -- To uninstall, stop and remove the running containers from the root of the Generative AI Examples repository: - - ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/rag-app-text-chatbot.yaml down - $ docker compose -f deploy/compose/docker-compose-vectordb.yaml down - - ``` - -## Next Steps - -- Use the [](./using-sample-web-application.md). -- [](./vector-database.md) -- Run the sample Jupyter notebooks to learn about optional features. diff --git a/docs/query-decomposition.md b/docs/query-decomposition.md index 2781dd1ab..42af1760c 100644 --- a/docs/query-decomposition.md +++ b/docs/query-decomposition.md @@ -28,7 +28,7 @@ backlinks: none ## Example Features This example deploys a recursive query decomposition example for chat Q&A. -The example uses the llama2-70b chat model from an NVIDIA API Catalog endpoint for inference. +The example uses the Meta Llama 3 70B Instruct model from an NVIDIA API Catalog endpoint for inference. Query decomposition can perform RAG when the agent needs to access information from several different documents (also referred to as _chunks_) or to perform some computation on the answers. @@ -52,11 +52,11 @@ The agent continues to break down the question into subquestions until it has th - Multi-GPU - TRT-LLM - Model Location - - Triton + - NIM for LLMs - Vector Database -* - ai-llama2-70b - - ai-embed-qa-4 +* - meta/llama3-70b-instruct + - snowflake-arctic-embed-l - LangChain - QA chatbot - NO @@ -89,6 +89,14 @@ The following figure shows the sample topology: - Install Docker Engine and Docker Compose. Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). +- Login to Nvidia's docker registry. Please refer to [instructions](https://docs.nvidia.com/ngc/gpu-cloud/ngc-overview/index.html) to create account and generate NGC API key. This is needed for pulling in the secure base container used by all the examples. + + ```console + $ docker login nvcr.io + Username: $oauthtoken + Password: + ``` + - Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). @@ -107,33 +115,12 @@ The following figure shows the sample topology: export RIVA_FUNCTION_ID="" ``` -## Get an API Key for the Llama 2 70B API Endpoint - -% api-key-start - -Perform the following steps if you do not already have an API key. -You can use different model API endpoints with the same API key. - -1. Navigate to . - -1. Find the **Llama 2 70B** card and click the card. +## Get an API Key for the Llama 3 70B API Endpoint - ![Llama 2 70B model card](./images/llama-2-70b-card.png) - -1. Click **Get API Key**. - - ![API section of the model page.](./images/llama-2-generate-key.png) - -1. Click **Generate Key**. - - ![Generate key window.](./images/api-catalog-generate-api-key.png) - -1. Click **Copy Key** and then save the API key. - The key begins with the letters nvapi-. - - ![Key Generated window.](./images/key-generated.png) - -% api-key-end +```{include} ./api-catalog.md +:start-after: api-key-start +:end-before: api-key-end +``` ## Build and Start the Containers @@ -168,7 +155,11 @@ You can use different model API endpoints with the same API key. 4. Start the Milvus vector database: ```console - $ docker compose --env-file deploy/compose/compose.env -f deploy/compose/docker-compose-vectordb.yaml up -d milvus + $ docker compose \ + --env-file deploy/compose/compose.env \ + -f deploy/compose/docker-compose-vectordb.yaml \ + --profile llm-embedding \ + up -d milvus ``` *Example Output* @@ -204,4 +195,4 @@ You can use different model API endpoints with the same API key. Ensure that you upload documents and use the knowledge base to answer queries. - [](./vector-database.md) - Stop the containers by running `docker compose -f deploy/compose/rag-app-query-decomposition-agent.yaml down` and - `docker compose -f deploy/compose/docker-compose-vectordb.yaml down`. + `docker compose -f deploy/compose/docker-compose-vectordb.yaml --profile llm-embedding down`. diff --git a/docs/simple-example/code/api-catalog/boilerplate/simple-rag-api-catalog.yaml b/docs/simple-example/code/api-catalog/boilerplate/simple-rag-api-catalog.yaml index 074bc2cfc..7447ca614 100644 --- a/docs/simple-example/code/api-catalog/boilerplate/simple-rag-api-catalog.yaml +++ b/docs/simple-example/code/api-catalog/boilerplate/simple-rag-api-catalog.yaml @@ -11,7 +11,7 @@ services: environment: APP_LLM_MODELNAME: ai-mixtral-8x7b-instruct APP_LLM_MODELENGINE: nvidia-ai-endpoints - APP_EMBEDDINGS_MODELNAME: ai-embed-qa-4 + APP_EMBEDDINGS_MODELNAME: snowflake/arctic-embed-l APP_EMBEDDINGS_MODELENGINE: nvidia-ai-endpoints APP_TEXTSPLITTER_CHUNKSIZE: 1200 APP_TEXTSPLITTER_CHUNKOVERLAP: 200 diff --git a/docs/simple-example/code/api-catalog/documents/chains.py b/docs/simple-example/code/api-catalog/documents/chains.py index c9299b2aa..4b7c2f79c 100644 --- a/docs/simple-example/code/api-catalog/documents/chains.py +++ b/docs/simple-example/code/api-catalog/documents/chains.py @@ -90,8 +90,10 @@ def delete_documents(self, filenames: List[str]): ids_list = [doc_id for doc_id, doc_data in in_memory_docstore.items() if extract_filename(doc_data.metadata) == filename] if vector_store.delete(ids_list): logger.info(f"Deleted document with file name: {filename}") + return True else: logger.error(f"Failed to delete document: {filename}") + return False except Exception as e: logger.error(f"Vector store not initialized. Error details: {e}") diff --git a/docs/simple-example/code/api-catalog/ingest/chains.py b/docs/simple-example/code/api-catalog/ingest/chains.py index 17a141a92..7b66462d3 100644 --- a/docs/simple-example/code/api-catalog/ingest/chains.py +++ b/docs/simple-example/code/api-catalog/ingest/chains.py @@ -17,7 +17,6 @@ import os from langchain.vectorstores import FAISS -DOCS_DIR = os.path.abspath("./uploaded_files") vector_store_path = "vectorstore.pkl" vector_store = None # end-ingest-faiss @@ -31,10 +30,8 @@ def ingest_docs(self, data_dir: str, filename: str): """Code to ingest documents""" try: global vector_store - # Files are copied to DOCS_DIR in the common.server:upload_document method. - _path = os.path.join(DOCS_DIR, filename) - raw_documents = UnstructuredFileLoader(_path).load() + raw_documents = UnstructuredFileLoader(data_dir).load() if raw_documents: text_splitter = CharacterTextSplitter(chunk_size=settings.text_splitter.chunk_size, chunk_overlap=settings.text_splitter.chunk_overlap) diff --git a/docs/simple-example/output/api-catalog/search/response.json b/docs/simple-example/output/api-catalog/search/response.json index ac580eeeb..2782ba3b3 100644 --- a/docs/simple-example/output/api-catalog/search/response.json +++ b/docs/simple-example/output/api-catalog/search/response.json @@ -6,7 +6,7 @@ "score": 0 }, { - "content": "Model Embedding Framework Description Multi-GPU TRT-LLM NVIDIA Endpoints Triton Vector Database mixtral_8x7b nvolveqa_40k LangChain NVIDIA API Catalog endpoints chat bot [ code , docs ] No No Yes Yes Milvus or pgvector llama-2 e5-large-v2 LlamaIndex Canonical QA Chatbot [ code , docs ] Yes Yes No Yes Milvus or pgvector llama-2 all-MiniLM-L6-v2 LlamaIndex Chat bot, GeForce, Windows [ repo ] No Yes No No FAISS llama-2 nvolveqa_40k LangChain Chat bot with query decomposition agent [ code , docs ] No No Yes Yes Milvus or pgvector mixtral_8x7b nvolveqa_40k LangChain Minimilastic example: RAG with NVIDIA AI Foundation Models [ code , README ] No No Yes Yes FAISS mixtral_8x7b Deplot Neva-22b nvolveqa_40k Custom Chat bot with multimodal data [ code , docs ] No No Yes No Milvus or pvgector llama-2 e5-large-v2 LlamaIndex Chat bot with quantized LLM model [ docs ] Yes Yes No Yes Milvus or pgvector mixtral_8x7b none PandasAI Chat bot with structured data [ code , docs ] No No Yes No none llama-2 nvolveqa_40k LangChain Chat bot with multi-turn conversation [ code , docs ] No No Yes No Milvus or pgvector", + "content": "Model Embedding Framework Description Multi-GPU TRT-LLM NVIDIA Endpoints Triton Vector Database mixtral_8x7b ai-embed-qa-4 LangChain NVIDIA API Catalog endpoints chat bot [ code , docs ] No No Yes Yes Milvus or pgvector llama-2 e5-large-v2 LlamaIndex Canonical QA Chatbot [ code , docs ] Yes Yes No Yes Milvus or pgvector llama-2 all-MiniLM-L6-v2 LlamaIndex Chat bot, GeForce, Windows [ repo ] No Yes No No FAISS llama-2 nvolveqa_40k LangChain Chat bot with query decomposition agent [ code , docs ] No No Yes Yes Milvus or pgvector mixtral_8x7b nvolveqa_40k LangChain Minimilastic example: RAG with NVIDIA AI Foundation Models [ code , README ] No No Yes Yes FAISS mixtral_8x7b Deplot Neva-22b nvolveqa_40k Custom Chat bot with multimodal data [ code , docs ] No No Yes No Milvus or pvgector llama-2 e5-large-v2 LlamaIndex Chat bot with quantized LLM model [ docs ] Yes Yes No Yes Milvus or pgvector mixtral_8x7b none PandasAI Chat bot with structured data [ code , docs ] No No Yes No none llama-2 nvolveqa_40k LangChain Chat bot with multi-turn conversation [ code , docs ] No No Yes No Milvus or pgvector", "filename": "README.md", "score": 0 }, diff --git a/docs/structured-data.md b/docs/structured-data.md index 051144d0c..48a6a4d78 100644 --- a/docs/structured-data.md +++ b/docs/structured-data.md @@ -28,7 +28,7 @@ backlinks: none ## Example Features This example deploys a developer RAG pipeline for chat Q&A and serves inferencing from an NVIDIA API Catalog endpoint -instead of NVIDIA Triton Inference Server, a local Llama 2 model, or local GPUs. +instead of a local inference server, local LLM, or local GPUs. Developers get free credits for 10K requests to any of the available models. @@ -64,12 +64,12 @@ Customization of the CSV data retrieval prompt is not supported. - Multi-GPU - TRT-LLM - Model Location - - Triton + - NIM for LLMs - Vector Database -* - ai-llama3-70b for response generation +* - meta/llama3-70b-instruct for response generation - ai-llama3-70b for PandasAI + meta/llama3-70b-instruct for PandasAI - Not Applicable - PandasAI - QA chatbot @@ -103,6 +103,14 @@ The following figure shows the sample topology: - Install Docker Engine and Docker Compose. Refer to the instructions for [Ubuntu](https://docs.docker.com/engine/install/ubuntu/). +- Login to Nvidia's docker registry. Please refer to [instructions](https://docs.nvidia.com/ngc/gpu-cloud/ngc-overview/index.html) to create account and generate NGC API key. This is needed for pulling in the secure base container used by all the examples. + + ```console + $ docker login nvcr.io + Username: $oauthtoken + Password: + ``` + - Optional: Enable NVIDIA Riva automatic speech recognition (ASR) and text to speech (TTS). - To launch a Riva server locally, refer to the [Riva Quick Start Guide](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). @@ -121,7 +129,7 @@ The following figure shows the sample topology: export RIVA_FUNCTION_ID="" ``` -## Get an API Key for the Mixtral 8x7B Instruct API Endpoint +## Get an API Key for the Llama 3 70B API Endpoint ```{include} api-catalog.md :start-after: api-key-start diff --git a/docs/support-matrix.md b/docs/support-matrix.md index bf8426dd7..74be347f1 100644 --- a/docs/support-matrix.md +++ b/docs/support-matrix.md @@ -29,9 +29,8 @@ backlinks: none Large Language Models are a heavily GPU-limited workflow. All LLMs are defined by the number of billions of parameters that make up their networks. -These generative AI examples focus on the Llama 2 Chat models from Meta. -These models are available in three different sizes: 7B, 13B, and 70B. -All three models perform well, but the 13B model is a good balance of performance and GPU memory utilization. +These generative AI examples focus on the Llama 3 Instruct models from Meta. +These models are available in two sizes: 8B and 70B. ```{list-table} :header-rows: 1 @@ -39,20 +38,12 @@ All three models perform well, but the 13B model is a good balance of performanc * - Model - GPU Memory Requirement -* - Llama-2-7B-Chat +* - Meta Llama 3 8B Instruct - 30 GB -* - Llama-2-13B-Chat - - 50 GB - -* - Llama-2-70B-Chat +* - Meta Llama 3 70B Instruct - 320 GB -* - Llama-2-7B-Chat AWQ Quantized - - 30 GB - -* - Nemotron-8B-Chat-SFT - - 100 GB ``` These resources can be provided by multiple GPUs on the same machine. @@ -80,17 +71,12 @@ The file size of the model varies according to the number of parameters in the m * - Model - Disk Storage -* - Llama-2-7B-Chat +* - Llama 3 8B Instruct - 30 GB -* - Llama-2-13B-Chat - - 50 GB - -* - Llama-2-70B-Chat - - 150 GB +* - Llama 3 70B Instruct + - 140 GB -* - Nemotron-8B-Chat-SFT - - 50 GB ``` The file space needed for the vector database varies by how many documents that you upload. diff --git a/docs/using-sample-web-application.md b/docs/using-sample-web-application.md index d4391e538..96e7fcbfc 100644 --- a/docs/using-sample-web-application.md +++ b/docs/using-sample-web-application.md @@ -27,7 +27,7 @@ backlinks: none ## Prerequisites -- You deployed one of the samples, such as [](./api-catalog.md) or [](./local-gpu.md). +- You deployed one of the samples, such as [](./api-catalog.md). ## Access the Web Application diff --git a/docs/vector-database.md b/docs/vector-database.md index 910618ba4..ea6638b7b 100644 --- a/docs/vector-database.md +++ b/docs/vector-database.md @@ -51,7 +51,7 @@ Alternatively, you can deploy pgvector. The preceding example shows the default values for the database user, password, and database. To override the defaults, edit the values in the Docker Compose file, or set the values in the `compose.env` file. - `Note`: If you have existing setup remove `deploy/compose/volumes` directory to avoid pgvector crash. + If you have existing setup remove `deploy/compose/volumes` directory to avoid pgvector crash. 1. Optional: If a container for a vector database is running, stop the container: @@ -86,7 +86,6 @@ Alternatively, you can deploy pgvector. 1. Confirm the log output includes the vector database: ```output - INFO:example:Ingesting .pdf in vectorDB INFO:RetrievalAugmentedGeneration.common.utils:Using pgvector as vector store INFO:RetrievalAugmentedGeneration.common.utils:Using PGVector collection: ``` @@ -139,7 +138,6 @@ Alternatively, you can deploy pgvector. 1. Confirm the log output includes the vector database: ```output - INFO:example:Ingesting .pdf in vectorDB INFO:RetrievalAugmentedGeneration.common.utils:Using milvus as vector store INFO:RetrievalAugmentedGeneration.common.utils:Using milvus collection: ``` diff --git a/docs/versions.json b/docs/versions.json index d29a613c2..e36ec4d18 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,6 +1,9 @@ { - "latest": "0.5.0", + "latest": "0.7.0", "versions": [ + { + "version": "0.7.0" + }, { "version": "0.5.0" } diff --git a/examples/5_mins_rag_no_gpu/main.py b/examples/5_mins_rag_no_gpu/main.py index 0c4207bcc..5640f8f59 100644 --- a/examples/5_mins_rag_no_gpu/main.py +++ b/examples/5_mins_rag_no_gpu/main.py @@ -47,17 +47,17 @@ from langchain_nvidia_ai_endpoints import ChatNVIDIA, NVIDIAEmbeddings # make sure to export your NVIDIA AI Playground key as NVIDIA_API_KEY! -llm = ChatNVIDIA(model="mixtral_8x7b") -document_embedder = NVIDIAEmbeddings(model="nvolveqa_40k", model_type="passage") -query_embedder = NVIDIAEmbeddings(model="nvolveqa_40k", model_type="query") +llm = ChatNVIDIA(model="ai-llama3-70b") +document_embedder = NVIDIAEmbeddings(model="ai-embed-qa-4", model_type="passage") +query_embedder = NVIDIAEmbeddings(model="ai-embed-qa-4", model_type="query") ############################################ # Component #3 - Vector Database Store ############################################ from langchain.text_splitter import CharacterTextSplitter -from langchain.document_loaders import DirectoryLoader -from langchain.vectorstores import FAISS +from langchain_community.document_loaders import DirectoryLoader +from langchain_community.vectorstores import FAISS import pickle with st.sidebar: @@ -116,14 +116,14 @@ [("system", "You are a helpful AI assistant named Envie. You will reply to questions only based on the context that you are provided. If something is out of context, you will refrain from replying and politely decline to respond to the user."), ("user", "{input}")] ) user_input = st.chat_input("Can you tell me what NVIDIA is known for?") -llm = ChatNVIDIA(model="mixtral_8x7b") +llm = ChatNVIDIA(model="ai-llama3-70b") chain = prompt_template | llm | StrOutputParser() if user_input and vectorstore!=None: st.session_state.messages.append({"role": "user", "content": user_input}) retriever = vectorstore.as_retriever() - docs = retriever.get_relevant_documents(user_input) + docs = retriever.invoke(user_input) with st.chat_message("user"): st.markdown(user_input) diff --git a/examples/5_mins_rag_no_gpu/requirements.txt b/examples/5_mins_rag_no_gpu/requirements.txt index a82c08db2..abd21ba65 100644 --- a/examples/5_mins_rag_no_gpu/requirements.txt +++ b/examples/5_mins_rag_no_gpu/requirements.txt @@ -1,5 +1,5 @@ streamlit==1.30.0 -langchain-nvidia-ai-endpoints==0.0.1 faiss-cpu==1.7.4 -langchain==0.0.352 +langchain==0.1.20 unstructured[all-docs]==0.11.2 +langchain-nvidia-ai-endpoints==0.0.19 diff --git a/experimental/README.md b/experimental/README.md index 14a4dc9d5..e7e5279f4 100644 --- a/experimental/README.md +++ b/experimental/README.md @@ -47,3 +47,11 @@ Experimental examples are sample code and deployments for RAG pipelines that are This example shows the configuration changes to using Docker containers and local GPUs that are required to run the RAG-LLM pipelines in Azure Machine Learning. + +* [NVIDIA Developer RAG Chatbot](./rag-developer-chatbot) + + This example shows how to create a developer-focused RAG chatbot using RAPIDS cuDF source code and API documentation as a representative example of a typical codebase. + +* [NVIDIA Event Driven RAG for CVE Analysis with NVIDIA Morpheus](./event-driven-rag-cve-analysis/) + + This example demonstrates how NVIDIA Morpheus, NIMs, and RAG pipelines can be integrated to create LLM-based agent pipelines. These pipelines will be used to automatically and scalably traige and detect Common Vulnerabilities and Exposures (CVEs) in Docker containers using references to source code, dependencies, and information about the CVEs. \ No newline at end of file diff --git a/experimental/event-driven-rag-cve-analysis/Dockerfile b/experimental/event-driven-rag-cve-analysis/Dockerfile new file mode 100755 index 000000000..c7dc661d8 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/Dockerfile @@ -0,0 +1,70 @@ +# syntax=docker/dockerfile:1.3 + +# SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG MORPHEUS_CONTAINER=nvcr.io/nvidia/morpheus/morpheus +ARG MORPHEUS_CONTAINER_VERSION=v24.03.00-dev + +FROM ${MORPHEUS_CONTAINER}:${MORPHEUS_CONTAINER_VERSION} as base + +WORKDIR /workspace + +# # Use a separate build directory to avoid clashes on the host +# ENV BUILD_DIR=build-docker + +# Make it easier to run commands in the container +ENV SHELL=/bin/bash + +# Copy over just the environment file to install the dependencies without busting the cache from source file changes +COPY ./requirements.yaml . + +# Install the example's dependencies +RUN source activate morpheus \ + && mamba env update -n morpheus -f ./requirements.yaml + +# Copy everything over to the container to build +COPY . ./ + +RUN chmod +x /workspace/entrypoint.sh + +# # If any changes have been made from the base image, recopy the sources +# COPY ./examples/cyber_dev_day /workspace/examples/cyber_dev_day/ + +# ===== Setup for running unattended ===== +FROM base as runtime + +# # Install the Workflow package +# RUN source activate morpheus \ +# && pip install -e . + +# # Keep the container running indefinitely +# CMD ["sleep", "infinity"] + +# ===== Setup for running Jupyter ===== +FROM base as jupyter + +# Install the jupyter specific requirements +RUN source activate morpheus &&\ + mamba install -y -c conda-forge \ + ipywidgets \ + jupyter_contrib_nbextensions \ + # notebook v7 is incompatible with jupyter_contrib_nbextensions + notebook=6 &&\ + jupyter contrib nbextension install --user &&\ + pip install jupyterlab_nvdashboard==0.9 + +# Launch jupyter +CMD ["jupyter-lab", "--ip=0.0.0.0", "--no-browser", "--allow-root"] diff --git a/experimental/event-driven-rag-cve-analysis/README.md b/experimental/event-driven-rag-cve-analysis/README.md new file mode 100644 index 000000000..1bf2d83c9 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/README.md @@ -0,0 +1,110 @@ + + +# Event Driven RAG and Agents with NVIDIA Morpheus +Determining the impact of a documented CVE on a specific project or container is a labor-intensive and manual task. This intricate process involves the collection, comprehension, and synthesis of various pieces of information to ascertain whether immediate remediation, such as patching, is necessary upon the identification of a new CVE. + +Our team developed a cybersecurity vulnerability analysis tool to aid in assessing the exploitability of CVEs in specific projects and containers. This tutorial will guide you step-by-step through the process of using LLMs, Retrieval-Augmented Generation (RAG), and agents to create both a toy version and a microservice running LLM-powered CVE exploitability analysis. + +## Prerequisites + +To run this example, you will need to have the access to `build.nvidia.com` and API credits to access the hosted LLMs. These are necessary to support running LLMs which are the focus of the Cyber Developer Day. + +You will also need to have a `Morpheus 24.03` docker container built and present in the environment. + +### NVIDIA GPU Cloud + +To access the NVIDIA hosted Inference Service, you will need to have the following environment variables set: `OPENAI_API_KEY`. To obtain the API key, please visit the [NVIDIA website](https://build.nvidia.com/) for instructions on generating your API key. + +It's important to note here that although we store the NGC API Key under the `OPENAI_API_KEY` variable, we will be interacting with NVIDIA hosted LLMs and not OpenAI LLMs. + +NVIDIA NIMs are OpenAI API compliant to maximize usability, so we will be using the `openai` with package as a wrapped to make API calls. +### Building a Morpheus Container + +This notebook has originally been designed to run with the NVIDIA AI Enterprise Morpheus container from NGC: + +```bash +nvcr.io/nvidia/morpheus/morpheus:v24.03.02-runtime +``` + +If you do not have access to NVIDIA AI Enterprise containers, you can follow instructions to build from source at the [Morpheus Repository](https://github.com/nv-morpheus/Morpheus/tree/branch-24.03). + +If you are using a Morpheus version that is not `v24.03.02-runtime`, please update the version argument in the `docker-compose.yml` file as follows: + +```bash + args: + - MORPHEUS_CONTAINER=${MORPHEUS_CONTAINER:-nvcr.io/nvidia/morpheus/morpheus} + - MORPHEUS_CONTAINER_VERSION=${MORPHEUS_CONTAINER_VERSION:-v24.03.02-runtime} +``` +### Creating an Environment File + +To automatically use these API keys, you can set the `OPENAI_API_KEY` value in the `docker-compose.yml` file in this directory as follows: + +```bash + environment: + - TERM=${TERM:-} + # Workaround until this is working: https://github.com/docker/compose/issues/9181#issuecomment-1996016211 + - OPENAI_API_KEY= + # Overwrite any environment variables in the .env file with URLs needed in the network + - OPENAI_API_BASE=https://integrate.api.nvidia.com/v1 + - OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1 +``` + +### Pulling Large Files from GIT LFS + +If you do not have Git LFS installed, install it using instructions at this [link](https://docs.github.com/en/repositories/working-with-files/managing-large-files/installing-git-large-file-storage). + +Run the following command from inside this repository's directory to pull down large files using Git LFS. + +```bash +git lfs pull +``` +## Build Instructions +You can build the required containers to run the workflow by running the following command in your terminal from this directory. + ```bash + docker compose build cyber-dev-day + ``` +## Running the Cyber Developer Day Content + +The Cyber Developer Day content is designed to be run using the `docker compose` command. The main entry point is the `cyber-dev-day` container, which is built in the previous step. This container launches a JupyterLab server with the necessary environment variables set to access the NeMo Inference Service and NVIDIA AI Foundation Models API. From there, the pipelines and all content can be run from JupyterLab. + +### Launching the Container and Connecting to JupyterLab + +To run the Cyber Developer Day content, use the following command: +```bash +docker compose up cyber-dev-day +``` + +Once launched, you should see a link in the output to connect to the JupyterLab server. Open this link in your web browser to access the content. For example: +``` +cyber-dev-day-1 | To access the server, open this file in a browser: +cyber-dev-day-1 | file:///root/.local/share/jupyter/runtime/jpserver-7-open.html +cyber-dev-day-1 | Or copy and paste one of these URLs: +cyber-dev-day-1 | http://localhost:8888/lab?token=a2d7504f70a2f5407236be5897ee266dc24bf19b01c222bc +cyber-dev-day-1 | http://127.0.0.1:8888/lab?token=a2d7504f70a2f5407236be5897ee266dc24bf19b01c222bc +``` + +### Running the Notebook + +Once connected to the JupyterLab server, you can navigate to the `notebooks` directory and open the `cyber-dev-day.ipynb` Notebook. The notebook contains the instructions and all of the necessary content to run the Cyber Developer Day. + +### Stopping the Container + +To stop the container, use the following command: +```bash +docker compose down +``` diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/__init__.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/__init__.py new file mode 100644 index 000000000..f6aa0d20f --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/__init__.py @@ -0,0 +1,35 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import logging +import sys + +morpheus_logger = logging.getLogger("morpheus") + +if (not getattr(morpheus_logger, "_configured_by_morpheus", False)): + + # Set the morpheus logger to propagate upstream + morpheus_logger.propagate = False + + # Add a default handler to the morpheus logger to print to screen + morpheus_logger.addHandler(logging.StreamHandler(stream=sys.stdout)) + + # Set a flag to indicate that the logger has been configured by Morpheus + setattr(morpheus_logger, "_configured_by_morpheus", True) + +logger = logging.getLogger(__name__) + +# Set the parent logger for the entire package to use morpheus so we can take advantage of configure_logging +logger.parent = morpheus_logger diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/checklist_node.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/checklist_node.py new file mode 100644 index 000000000..15d117b88 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/checklist_node.py @@ -0,0 +1,266 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import ast +import logging +import re +from textwrap import dedent + +from morpheus.llm import LLMLambdaNode +from morpheus.llm import LLMNode +from morpheus.llm.nodes.llm_generate_node import LLMGenerateNode +from morpheus.llm.nodes.prompt_template_node import PromptTemplateNode +from cyber_dev_day.llm_service import LLMService + +from .config import EngineChecklistConfig + +logger = logging.getLogger(__name__) + +# checklist_prompt_template = dedent(""" +# This is an example of CVE information and a checklist produced to determine if the given CVE is exploitable in a containerized environment: +# (1) CVE information: The email module of Python through 3.11.3 incorrectly parses e-mail addresses that contain a special character. The wrong portion of an RFC2822 header is identified as the value of the addr-spec. In some applications, an attacker can bypass a protection mechanism in which application access is granted only after verifying receipt of e-mail to a specific domain (e.g., only @company.example.com addresses may be used for signup). This occurs in email/_parseaddr.py in recent versions of Python. +# (2) Checklist: +# 1. Check the version of python. The vulnerability affects python through 3.11.3. +# 2. Check if the code base uses email functionality in python. + +# Given the following cve information, make a checklist for security analysts to follow to determine whether a Docker container is vulnerable to this exploit. +# CVE information: {{cve_info}} + +# Checklist: + +# """).strip("\n") + +checklist_prompt_template = dedent( + """You are an expert security analyst. Your objective is to add a "Checklist" section containing steps to use when assessing the exploitability of a specific CVE within a containerized environment. \ +For each checklist item, start with an action verb, making it clear and actionable + +**Context**: +Not all CVEs are exploitable in a given container. By making a checklist specific to the information available for a given CVE analysts can execute the checklist to determine exploitability. + +**Example Format**: +Below is a format for examples that illustrate transforming CVE information into an exploitability assessment checklist. + +Example 1 CVE Details: +- CVE ID: CVE-2022-2309 +- Description: NULL Pointer Dereference allows attackers to cause a denial of service (or application crash). This only applies when lxml up to version 4.9.1 \ +is used together with libxml2 2.9.10 through 2.9.14. libxml2 2.9.9 and earlier are not affected. It allows triggering crashes through forged input data, given a \ +vulnerable code sequence in the application. The vulnerability is caused by the iterwalk function (also used by the canonicalize function). Such code shouldn't be \ +in wide-spread use, given that parsing + iterwalk would usually be replaced with the more efficient iterparse function. However, an XML converter that serialises to \ +C14N would also be vulnerable, for example, and there are legitimate use cases for this code sequence. If untrusted input is received (also remotely) and processed via \ +iterwalk function, a crash can be triggered. +- Vulnerable Package Name: lxml, libxml2 +- Vulnerable Package Version: lxml: up to 4.9.1, libxml2: 2.91.0 through 2.9.14 +- CVSS3 Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H + +Example 1 Exploitability Assessment Checklist: +[ +"Check for lxml: Verify if your project uses the lxml library, which is the affected package. If lxml is not a dependency in your project, then your code is not vulnerable to this CVE.", +"Review Affected Versions: If lxml is used, checked the version that your project depends on. According to the vulnerability details, versions 4.9.0 and earlier are vulnerable.", +"Review Versions of Connected Dependencies: The package is only vulnerable if libxml 2.9.10 through 2.9.14 is also present. Check the version of libxml in the project.", +"Check for use of vulnerable functions: The library is vulnerable through its `iterwalk` function, which is also utilized by the `canonicalize` function. Check if either of these functions are used in your code base." +] + +Example 2 CVE Details: +- CVE ID: CVE-2024-23334 +- Description: aiohttp is an asynchronous HTTP client/server framework for asyncio and Python. When using aiohttp as a web server and configuring static routes, \ +it is necessary to specify the root path for static files. Additionally, the option 'follow_symlinks' can be used to determine whether to follow symbolic links \ +outside the static root directory. When 'follow_symlinks' is set to True, there is no validation to check if reading a file is within the root directory. This can \ +lead to directory traversal vulnerabilities, resulting in unauthorized access to arbitrary files on the system, even when symlinks are not present. \ +Disabling `follow_symlinks` by setting `follow_symlinks = False` and using a reverse proxy are encouraged mitigations. Version 3.9.2 fixes this issue. +- Vulnerable Package Name: aiohttp +- Vulnerable Package Version: from 1.0.5 up to (excluding) 3.9.2 +- CVSS3 Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N + +Example 2 Exploitability Assessment Checklist: +[ + "Check for aiohttp: Verify if your project uses the aiohttp library, which is the affected package. If aiohttp is not a dependency in your project, then your code is not vulnerable to this CVE.", + "Review Affected Versions: If aiohttp is used, check the version that your project depends on. According to the vulnerability details, versions from 1.0.5 up to (excluding) 3.9.2 are affected by this vulnerability.", + "Review Code To Check for Vulnerability Mitigation: Check if the 'follow_symlinks' option is set to False to mitigate the risk of directory traversal vulnerabilities." +] + +**Criteria**: +- Exploitability assessment checklists must relate to the information in the specific CVE Details. +- Exploitability assessment checklists must include checks for mitigating conditions when present in the CVE Details. + +**Procedure**: +[ +"Understand the CVE Details, description, and CVSS3 attack vector string.", +"Produce a CVE exploitability assessment checklist.", +"Format the checklist as comma separated list surrounded by square braces.", +"Output the checklist." +] + +**CVE Details:** +{{cve_details}} + +**Checklist**: + +Please only provide the comma separated, python formatted list, no other text. """).strip("\n") + +parselist_prompt_template = dedent(""" +Parse the following numbered checklist's contents into a python list in the format ['x', 'y', 'z'], a comma separated list surrounded by square braces. For example, the following checklist: + +1. Check for notable vulnerable software vendors +2. Consider the network exposure of your Docker container + +Should generate: ["Check for notable vulnerable software vendors", "Consider the network exposure of your Docker container"] + +Checklist: +{{template}} + +Please only provide the comma separated, python formatted, list.""").strip("\n") + +# Find all substrings that start and end with quotes, allowing for spaces before a comma or closing bracket +re_quote_capture = re.compile( + r""" + (['"]) # Opening quote + ( # Start capturing the quoted content + (?:\\.|[^\\])*? # Non-greedy match for any escaped character or non-backslash character + ) # End capturing the quoted content + \1 # Matching closing quote + (?=\s*,|\s*\]) # Lookahead for whitespace followed by a comma or closing bracket, without including it in the match + """, + re.VERBOSE) + + +def attempt_fix_list_string(s: str) -> str: + """ + Attempt to fix unescaped quotes in a string that represents a list to make it parsable. + + Parameters + ---------- + s : str + A string representation of a list that potentially contains unescaped quotes. + + Returns + ------- + str + The corrected string where internal quotes are properly escaped, ensuring it can be parsed as a list. + + Notes + ----- + This function is useful for preparing strings to be parsed by `ast.literal_eval` by ensuring that quotes inside + the string elements of the list are properly escaped. It adds brackets at the beginning and end if they are missing. + """ + # Check if the input starts with '[' and ends with ']' + s = s.strip() + if (not s.startswith('[')): + s = "[" + s + if (not s.endswith(']')): + s = s + "]" + + def fix_quotes(match): + # Extract the captured groups + quote_char, content = match.group(1), match.group(2) + # Escape quotes inside the string content + fixed_content = re.sub(r"(? list[list[str]]: + """ + Asynchronously parse a list of strings, each representing a list, into a list of lists. + + Parameters + ---------- + text : list of str + A list of strings, each intended to be parsed into a list. + + Returns + ------- + list of lists of str + A list of lists, parsed from the input strings. + + Raises + ------ + ValueError + If the string cannot be parsed into a list or if the parsed object is not a list. + + Notes + ----- + This function tries to fix strings that represent lists with unescaped quotes by calling + `attempt_fix_list_string` and then uses `ast.literal_eval` for safe parsing of the string into a list. + It ensures that each element of the parsed list is actually a list and will raise an error if not. + """ + return_val = [] + + for x in text: + try: + # Try to do some very basic string cleanup to fix unescaped quotes + x = attempt_fix_list_string(x) + + # Only proceed if the input is a valid Python literal + # This isn't really dangerous, literal_eval only evaluates a small subset of python + current = ast.literal_eval(x) + + # Ensure that the parsed data is a list + if not isinstance(current, list): + raise ValueError(f"Input is not a list: {x}") + + # Process the list items + for i in range(len(current)): + if (isinstance(current[i], list) and len(current[i]) == 1): + current[i] = current[i][0] + + return_val.append(current) + except (ValueError, SyntaxError) as e: + # Handle the error, log it, or re-raise it with additional context + raise ValueError(f"Failed to parse input {x}: {e}") + + return return_val + + +class CVEChecklistNode(LLMNode): + """ + A node that orchestrates the process of generating a checklist for CVE (Common Vulnerabilities and Exposures) items. + It integrates various nodes that handle CVE lookup, prompting, generation, and parsing to produce an actionable checklist. + """ + + def __init__(self, *, config: EngineChecklistConfig): + """ + Initialize the CVEChecklistNode with optional caching and a vulnerability endpoint retriever. + + Parameters + ---------- + model_name : str, optional + The name of the language model to be used for generating text, by default "gpt-3.5-turbo". + cache_dir : str, optional + The directory where the node's cache should be stored. If None, caching is not used. + vuln_endpoint_retriever : object, optional + An instance of a vulnerability endpoint retriever. If None, defaults to `NISTCVERetriever`. + """ + super().__init__() + + self._config = config + + llm_service = LLMService.create(config.model.service.type, **config.model.service.model_dump(exclude={"type"})) + + # Add a node to create a prompt for CVE checklist generation based on the CVE details obtained from the lookup + # node + self.add_node("checklist_prompt", + inputs=[("*", "*")], + node=PromptTemplateNode(template=checklist_prompt_template, template_format="jinja")) + + # Instantiate a chat service and configure a client for generating responses to the checklist prompt + llm_client_1 = llm_service.get_client(**config.model.model_dump(exclude={"service"})) + self.add_node("generate_checklist", inputs=["/checklist_prompt"], node=LLMGenerateNode(llm_client=llm_client_1)) + + # Add an output parser node to process the final generated checklist into a structured list + self.add_node("output_parser", inputs=["/generate_checklist"], node=LLMLambdaNode(_parse_list), is_output=True) diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/config.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/config.py new file mode 100644 index 000000000..30249e4a1 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/config.py @@ -0,0 +1,127 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License + +import typing +from pydantic import BaseModel +from pydantic import Discriminator +from pydantic import Field +from pydantic import Tag + + +def _llm_discriminator(v: typing.Any) -> str: + if isinstance(v, dict): + return v.get("service").get("type") + return getattr(getattr(v, "service"), "type") + + +class NeMoLLMServiceConfig(BaseModel): + type: typing.Literal["nemo"] = "nemo" + + api_key: str | None = None + org_id: str | None = None + + +class NeMoLLMModelConfig(BaseModel): + service: NeMoLLMServiceConfig + + model_name: str + customization_id: str | None = None + temperature: float = 0.0 + top_k: int = 0 + tokens_to_generate: int = 300 + + +class NVFoundationLLMServiceConfig(BaseModel): + type: typing.Literal["nvfoundation"] = "nvfoundation" + + api_key: str | None = None + + +class NVFoundationLLMModelConfig(BaseModel): + service: NVFoundationLLMServiceConfig + + model_name: str + temperature: float = 0.0 + + +class OpenAIServiceConfig(BaseModel): + type: typing.Literal["openai"] = "openai" + + +class OpenAIMModelConfig(BaseModel): + service: OpenAIServiceConfig + + model_name: str + + +class NIMServiceConfig(BaseModel): + type: typing.Literal["NIM"] = "NIM" + + +class NIMModelConfig(BaseModel): + service: NIMServiceConfig + + model_name: str + base_url: str + temperature: float = 0.0 + top_p: float = 1 + + +LLMModelConfig = typing.Annotated[typing.Annotated[NeMoLLMModelConfig, Tag("nemo")] + | typing.Annotated[OpenAIMModelConfig, Tag("openai")] + | typing.Annotated[NVFoundationLLMModelConfig, Tag("nvfoundation")] + | typing.Annotated[NIMModelConfig, Tag("NIM")], +Discriminator(_llm_discriminator)] + + +class HttpServerInputConfig(BaseModel): + type: typing.Literal["http_server"] = "http_server" + + +class NspectFileInputConfig(BaseModel): + type: typing.Literal["nspect_file"] = "nspect_file" + + +class CveFileInputConfig(BaseModel): + type: typing.Literal["cve_file"] = "cve_file" + + +class EngineChecklistConfig(BaseModel): + model: LLMModelConfig + + +class EngineSBOMConfig(BaseModel): + data_file: str + + +class EngineCodeRepoConfig(BaseModel): + faiss_dir: str + + embedding_model_name: str = "sentence-transformers/all-mpnet-base-v2" + + +class EngineAgentConfig(BaseModel): + model: LLMModelConfig + + sbom: EngineSBOMConfig + + code_repo: EngineCodeRepoConfig + + verbose: bool = True + + +class EngineConfig(BaseModel): + checklist: EngineChecklistConfig + + agent: EngineAgentConfig diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/embeddings.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/embeddings.py new file mode 100644 index 000000000..c9635ff91 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/embeddings.py @@ -0,0 +1,152 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os +import pathlib + +import nbformat +from langchain.docstore.document import Document +from langchain.document_loaders.parsers import LanguageParser +from langchain.text_splitter import Language +from langchain.text_splitter import RecursiveCharacterTextSplitter +from langchain.vectorstores.faiss import FAISS +from langchain_community.document_loaders.blob_loaders.schema import Blob +from langchain_core.embeddings import Embeddings + +logger = logging.getLogger(f"__name__") + + +def _extract_python_code_from_ipynb(notebook_content: str, cell_type: str = "code"): + """Extract python code from jupyter notebook + + Parameters + ---------- + notebook_content : str + notebook content location + cell_type : str, optional + _description_, by default "code" + + Returns + ------- + str + python codes + """ + + notebook = nbformat.read(notebook_content, as_version=nbformat.NO_CONVERT) + + python_code = [] + for cell in notebook.cells: + if cell.cell_type == cell_type: + python_code.append(cell.source) + + return "\n".join(python_code) + + +def _read_gitignore_exclusions(gitignore_file: str, base_dir: str) -> list[str]: + exclusions = [] + + # Load the gitignore file + with open(os.path.join(base_dir, ".gitignore"), "r") as ignore_file: + for line in ignore_file: + # Remove any leading or trailing whitespace + line = line.strip() + + # Ignore comments and empty lines + if not line or line.startswith("#"): + continue + + # Unescape # characters + if line[0] == '\\' and line[1] in ('#', '!'): + line = line[1:] + + # Add the line to the list of exclusions + if ("/" in line): + exclusions.append(os.path.normpath(os.path.join(base_dir, line.removeprefix("/")))) + else: + exclusions.append(line) + + return exclusions + + +def create_code_embedding(code_dir: str, + embedding: Embeddings, + include: str = "**/*.py", + exclude: list[str] = None, + include_notebooks: bool = False): + """ + Create code embedding from specified code directory. + """ + documents: list[Document] = [] + logger.info(f"Generating embedding for source code in {code_dir}") + + # include notebooks + if include_notebooks: + + for nb in pathlib.Path(code_dir).glob("**/[!.]*.ipynb"): + content = _extract_python_code_from_ipynb(str(nb)) + if content: + documents.append(Document(page_content=content, metadata={'source': nb, 'language': Language.PYTHON})) + + final_exclusions = exclude or [] + + # # Load the gitignore file to pre-populate the exclude list + # if (os.path.exists(os.path.join(code_dir, ".gitignore"))): + # # Load the gitignore file + # final_exclusions.extend(_read_gitignore_exclusions(os.path.join(code_dir, ".gitignore"), code_dir)) + + code_path = pathlib.Path(code_dir) + + parser = LanguageParser(language=Language.PYTHON.value, parser_threshold=500) + + positive_matches = set(code_path.glob(include)) + + for exclusion in final_exclusions: + negative_matches = set(code_path.glob(exclusion)) + positive_matches -= negative_matches + + def build_documents(matches): + + for path in matches: + + blob = Blob.from_path(path) + + yield from parser.lazy_parse(blob) + + documents.extend(build_documents(sorted(positive_matches))) + + logger.info(f"Total {len(documents)} source code documents in {len(positive_matches)} files.") + + debug_file_path = f"{os.getenv('MORPHEUS_ROOT', '.')}/.tmp/embedding_file_list.txt" + + # Ensure the directory exists + os.makedirs(os.path.dirname(debug_file_path), exist_ok=True) + + # Write out the list of files to disk to analyze + with open(debug_file_path, mode="w", encoding="utf-8") as f: + f.writelines([f".{doc.metadata['source'].removeprefix(code_dir)}\n" for doc in documents]) + + python_splitter = RecursiveCharacterTextSplitter.from_language(language=Language.PYTHON, + chunk_size=1000, + chunk_overlap=200) + code_documents = python_splitter.split_documents(documents) + + logger.info("Creating embeddings...") + + # create embeddings + db = FAISS.from_documents(code_documents, embedding) + + logger.info("Creating embeddings... Complete") + + return db diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/faiss_vdb_service.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/faiss_vdb_service.py new file mode 100644 index 000000000..81f63aef5 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/faiss_vdb_service.py @@ -0,0 +1,765 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +import copy +import json +import logging +import threading +import time +import typing +from functools import wraps + +import pandas as pd + +import cudf + +from morpheus.service.vdb.vector_db_service import VectorDBResourceService +from morpheus.service.vdb.vector_db_service import VectorDBService + +logger = logging.getLogger(__name__) + +IMPORT_EXCEPTION = None +IMPORT_ERROR_MESSAGE = "MilvusVectorDBResourceService requires the milvus and pymilvus packages to be installed." + +try: + from langchain.vectorstores.faiss import FAISS +except ImportError as import_exc: + IMPORT_EXCEPTION = import_exc + + +class FaissVectorDBResourceService(VectorDBResourceService): + """ + Represents a service for managing resources in a Milvus Vector Database. + + Parameters + ---------- + name : str + Name of the resource. + client : MilvusClient + An instance of the MilvusClient for interaction with the Milvus Vector Database. + """ + + def __init__(self, parent: "FaissVectorDBService", *, name: str) -> None: + if IMPORT_EXCEPTION is not None: + raise ImportError(IMPORT_ERROR_MESSAGE) from IMPORT_EXCEPTION + + super().__init__() + + self._parent = parent + self._name = name + + self._index = FAISS.load_local(folder_path=self._parent._local_dir, + embeddings=self._parent._embeddings, + index_name=self._name, + allow_dangerous_deserialization=True) + + def insert(self, data: list[list] | list[dict], **kwargs: dict[str, typing.Any]) -> dict: + """ + Insert data into the vector database. + + Parameters + ---------- + data : list[list] | list[dict] + Data to be inserted into the collection. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + dict + Returns response content as a dictionary. + """ + raise NotImplementedError("Insert operation is not supported in FAISS") + + def insert_dataframe(self, df: typing.Union[cudf.DataFrame, pd.DataFrame], **kwargs: dict[str, typing.Any]) -> dict: + """ + Insert a dataframe entires into the vector database. + + Parameters + ---------- + df : typing.Union[cudf.DataFrame, pd.DataFrame] + Dataframe to be inserted into the collection. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + dict + Returns response content as a dictionary. + """ + raise NotImplementedError("Insert operation is not supported in FAISS") + + def describe(self, **kwargs: dict[str, typing.Any]) -> dict: + """ + Provides a description of the collection. + + Parameters + ---------- + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + dict + Returns response content as a dictionary. + """ + raise NotImplementedError("Describe operation is not supported in FAISS") + + def query(self, query: str, **kwargs: dict[str, typing.Any]) -> typing.Any: + """ + Query data in a collection in the Milvus vector database. + + This method performs a search operation in the specified collection/partition in the Milvus vector database. + + Parameters + ---------- + query : str, optional + The search query, which can be a filter expression, by default None. + **kwargs : dict + Additional keyword arguments for the search operation. + + Returns + ------- + typing.Any + The search result, which can vary depending on the query and options. + + Raises + ------ + RuntimeError + If an error occurs during the search operation. + If query argument is `None` and `data` keyword argument doesn't exist. + If `data` keyword arguement is `None`. + """ + raise NotImplementedError("Query operation is not supported in FAISS") + + async def similarity_search(self, + embeddings: list[list[float]], + k: int = 4, + **kwargs: dict[str, typing.Any]) -> list[list[dict]]: + """ + Perform a similarity search within the collection. + + Parameters + ---------- + embeddings : list[list[float]] + Embeddings for which to perform the similarity search. + k : int, optional + The number of nearest neighbors to return, by default 4. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + list[dict] + Returns a list of dictionaries representing the results of the similarity search. + """ + + async def single_search(single_embedding): + docs = await self._index.asimilarity_search_by_vector(embedding=single_embedding, k=k) + + return [d.dict() for d in docs] + + return list(await asyncio.gather(*[single_search(embedding) for embedding in embeddings])) + + def update(self, data: list[typing.Any], **kwargs: dict[str, typing.Any]) -> dict[str, typing.Any]: + """ + Update data in the collection. + + Parameters + ---------- + data : list[typing.Any] + Data to be updated in the collection. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to upsert operation. + + Returns + ------- + dict[str, typing.Any] + Returns result of the updated operation stats. + """ + raise NotImplementedError("Update operation is not supported in FAISS") + + def delete_by_keys(self, keys: int | str | list, **kwargs: dict[str, typing.Any]) -> typing.Any: + """ + Delete vectors by keys from the collection. + + Parameters + ---------- + keys : int | str | list + Primary keys to delete vectors. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + typing.Any + Returns result of the given keys that are deleted from the collection. + """ + raise NotImplementedError("Delete by keys operation is not supported in FAISS") + + def delete(self, expr: str, **kwargs: dict[str, typing.Any]) -> dict[str, typing.Any]: + """ + Delete vectors from the collection using expressions. + + Parameters + ---------- + expr : str + Delete expression. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + dict[str, typing.Any] + Returns result of the given keys that are deleted from the collection. + """ + raise NotImplementedError("Delete operation is not supported in FAISS") + + def retrieve_by_keys(self, keys: int | str | list, **kwargs: dict[str, typing.Any]) -> list[typing.Any]: + """ + Retrieve the inserted vectors using their primary keys. + + Parameters + ---------- + keys : int | str | list + Primary keys to get vectors for. Depending on pk_field type it can be int or str + or a list of either. + **kwargs : dict[str, typing.Any] + Additional keyword arguments for the retrieval operation. + + Returns + ------- + list[typing.Any] + Returns result rows of the given keys from the collection. + """ + raise NotImplementedError("Retrieve by keys operation is not supported in FAISS") + + def count(self, **kwargs: dict[str, typing.Any]) -> int: + """ + Returns number of rows/entities. + + Parameters + ---------- + **kwargs : dict[str, typing.Any] + Additional keyword arguments for the count operation. + + Returns + ------- + int + Returns number of entities in the collection. + """ + raise NotImplementedError("Count operation is not supported in FAISS") + + def drop(self, **kwargs: dict[str, typing.Any]) -> None: + """ + Drop a collection, index, or partition in the Milvus vector database. + + This function allows you to drop a collection. + + Parameters + ---------- + **kwargs : dict + Additional keyword arguments for specifying the type and partition name (if applicable). + """ + raise NotImplementedError("Drop operation is not supported in FAISS") + + +class FaissVectorDBService(VectorDBService): + """ + Service class for Milvus Vector Database implementation. This class provides functions for interacting + with a Milvus vector database. + + Parameters + ---------- + host : str + The hostname or IP address of the Milvus server. + port : str + The port number for connecting to the Milvus server. + alias : str, optional + Alias for the Milvus connection, by default "default". + **kwargs : dict + Additional keyword arguments specific to the Milvus connection configuration. + """ + + _collection_locks = {} + _cleanup_interval = 600 # 10mins + _last_cleanup_time = time.time() + + def __init__(self, local_dir: str, embeddings, **kwargs: dict[str, typing.Any]): + + if IMPORT_EXCEPTION is not None: + raise ImportError(IMPORT_ERROR_MESSAGE) from IMPORT_EXCEPTION + + self._local_dir = local_dir + self._embeddings = embeddings + + def load_resource(self, name: str = "index", **kwargs: dict[str, typing.Any]) -> FaissVectorDBResourceService: + + return FaissVectorDBResourceService(self, name=name, **kwargs) + + def has_store_object(self, name: str) -> bool: + """ + Check if a collection exists in the Milvus vector database. + + Parameters + ---------- + name : str + Name of the collection to check. + + Returns + ------- + bool + True if the collection exists, False otherwise. + """ + return self._client.has_collection(collection_name=name) + + def list_store_objects(self, **kwargs: dict[str, typing.Any]) -> list[str]: + """ + List the names of all collections in the Milvus vector database. + + Returns + ------- + list[str] + A list of collection names. + """ + return self._client.list_collections(**kwargs) + + def _create_schema_field(self, field_conf: dict) -> "pymilvus.FieldSchema": + + field_schema = pymilvus.FieldSchema.construct_from_dict(field_conf) + + return field_schema + + def create(self, name: str, overwrite: bool = False, **kwargs: dict[str, typing.Any]): + """ + Create a collection in the Milvus vector database with the specified name and configuration. This method + creates a new collection in the Milvus vector database with the provided name and configuration options. + If the collection already exists, it can be overwritten if the `overwrite` parameter is set to True. + + Parameters + ---------- + name : str + Name of the collection to be created. + overwrite : bool, optional + If True, the collection will be overwritten if it already exists, by default False. + **kwargs : dict + Additional keyword arguments containing collection configuration. + + Raises + ------ + ValueError + If the provided schema fields configuration is empty. + """ + logger.debug("Creating collection: %s, overwrite=%s, kwargs=%s", name, overwrite, kwargs) + + # Preserve original configuration. + collection_conf = copy.deepcopy(kwargs) + + auto_id = collection_conf.get("auto_id", False) + index_conf = collection_conf.get("index_conf", None) + partition_conf = collection_conf.get("partition_conf", None) + + schema_conf = collection_conf.get("schema_conf") + schema_fields_conf = schema_conf.pop("schema_fields") + + if not self.has_store_object(name) or overwrite: + if overwrite and self.has_store_object(name): + self.drop(name) + + if len(schema_fields_conf) == 0: + raise ValueError("Cannot create collection as provided empty schema_fields configuration") + + schema_fields = [FieldSchemaEncoder.from_dict(field_conf) for field_conf in schema_fields_conf] + + schema = pymilvus.CollectionSchema(fields=schema_fields, **schema_conf) + + self._client.create_collection_with_schema(collection_name=name, + schema=schema, + index_params=index_conf, + auto_id=auto_id, + shards_num=collection_conf.get("shards", 2), + consistency_level=collection_conf.get( + "consistency_level", "Strong")) + + if partition_conf: + timeout = partition_conf.get("timeout", 1.0) + # Iterate over each partition configuration + for part in partition_conf["partitions"]: + self._client.create_partition(collection_name=name, partition_name=part["name"], timeout=timeout) + + def create_from_dataframe(self, + name: str, + df: typing.Union[cudf.DataFrame, pd.DataFrame], + overwrite: bool = False, + **kwargs: dict[str, typing.Any]) -> None: + """ + Create collections in the vector database. + + Parameters + ---------- + name : str + Name of the collection. + df : Union[cudf.DataFrame, pd.DataFrame] + The dataframe to create the collection from. + overwrite : bool, optional + Whether to overwrite the collection if it already exists. Default is False. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + """ + + fields = self._build_schema_conf(df=df) + + create_kwargs = { + "schema_conf": { + "description": "Auto generated schema from DataFrame in Morpheus", + "schema_fields": fields, + } + } + + if (kwargs.get("index_field", None) is not None): + # Check to make sure the column name exists in the fields + create_kwargs["index_conf"] = { + "field_name": kwargs.get("index_field"), # Default index type + "metric_type": "L2", + "index_type": "HNSW", + "params": { + "M": 8, + "efConstruction": 64, + }, + } + + self.create(name=name, overwrite=overwrite, **create_kwargs) + + def insert(self, name: str, data: list[list] | list[dict], **kwargs: dict[str, + typing.Any]) -> dict[str, typing.Any]: + """ + Insert a collection specific data in the Milvus vector database. + + Parameters + ---------- + name : str + Name of the collection to be inserted. + data : list[list] | list[dict] + Data to be inserted in the collection. + **kwargs : dict[str, typing.Any] + Additional keyword arguments containing collection configuration. + + Returns + ------- + dict + Returns response content as a dictionary. + + Raises + ------ + RuntimeError + If the collection not exists exists. + """ + + resource = self.load_resource(name) + return resource.insert(data, **kwargs) + + def insert_dataframe(self, + name: str, + df: typing.Union[cudf.DataFrame, pd.DataFrame], + **kwargs: dict[str, typing.Any]) -> dict[str, typing.Any]: + """ + Converts dataframe to rows and insert to a collection in the Milvus vector database. + + Parameters + ---------- + name : str + Name of the collection to be inserted. + df : typing.Union[cudf.DataFrame, pd.DataFrame] + Dataframe to be inserted in the collection. + **kwargs : dict[str, typing.Any] + Additional keyword arguments containing collection configuration. + + Returns + ------- + dict + Returns response content as a dictionary. + + Raises + ------ + RuntimeError + If the collection not exists exists. + """ + resource = self.load_resource(name) + + return resource.insert_dataframe(df=df, **kwargs) + + def query(self, name: str, query: str = None, **kwargs: dict[str, typing.Any]) -> typing.Any: + """ + Query data in a collection in the Milvus vector database. + + This method performs a search operation in the specified collection/partition in the Milvus vector database. + + Parameters + ---------- + name : str + Name of the collection to search within. + query : str + The search query, which can be a filter expression. + **kwargs : dict + Additional keyword arguments for the search operation. + + Returns + ------- + typing.Any + The search result, which can vary depending on the query and options. + """ + + resource = self.load_resource(name) + + return resource.query(query, **kwargs) + + async def similarity_search(self, name: str, **kwargs: dict[str, typing.Any]) -> list[dict]: + """ + Perform a similarity search within the collection. + + Parameters + ---------- + name : str + Name of the collection. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + list[dict] + Returns a list of dictionaries representing the results of the similarity search. + """ + + resource = self.load_resource(name) + + return resource.similarity_search(**kwargs) + + def update(self, name: str, data: list[typing.Any], **kwargs: dict[str, typing.Any]) -> dict[str, typing.Any]: + """ + Update data in the vector database. + + Parameters + ---------- + name : str + Name of the collection. + data : list[typing.Any] + Data to be updated in the collection. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to upsert operation. + + Returns + ------- + dict[str, typing.Any] + Returns result of the updated operation stats. + """ + + if not isinstance(data, list): + raise RuntimeError("Data is not of type list.") + + resource = self.load_resource(name) + + return resource.update(data=data, **kwargs) + + def delete_by_keys(self, name: str, keys: int | str | list, **kwargs: dict[str, typing.Any]) -> typing.Any: + """ + Delete vectors by keys from the collection. + + Parameters + ---------- + name : str + Name of the collection. + keys : int | str | list + Primary keys to delete vectors. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + typing.Any + Returns result of the given keys that are delete from the collection. + """ + + resource = self.load_resource(name) + + return resource.delete_by_keys(keys=keys, **kwargs) + + def delete(self, name: str, expr: str, **kwargs: dict[str, typing.Any]) -> dict[str, typing.Any]: + """ + Delete vectors from the collection using expressions. + + Parameters + ---------- + name : str + Name of the collection. + expr : str + Delete expression. + **kwargs : dict[str, typing.Any] + Extra keyword arguments specific to the vector database implementation. + + Returns + ------- + dict[str, typing.Any] + Returns result of the given keys that are delete from the collection. + """ + + resource = self.load_resource(name) + result = resource.delete(expr=expr, **kwargs) + + return result + + def retrieve_by_keys(self, name: str, keys: int | str | list, **kwargs: dict[str, typing.Any]) -> list[typing.Any]: + """ + Retrieve the inserted vectors using their primary keys from the Collection. + + Parameters + ---------- + name : str + Name of the collection. + keys : int | str | list + Primary keys to get vectors for. Depending on pk_field type it can be int or str + or a list of either. + **kwargs : dict[str, typing.Any] + Additional keyword arguments for the retrieval operation. + + Returns + ------- + list[typing.Any] + Returns result rows of the given keys from the collection. + """ + + resource = self.load_resource(name) + + result = resource.retrieve_by_keys(keys=keys, **kwargs) + + return result + + def count(self, name: str, **kwargs: dict[str, typing.Any]) -> int: + """ + Returns number of rows/entities in the given collection. + + Parameters + ---------- + name : str + Name of the collection. + **kwargs : dict[str, typing.Any] + Additional keyword arguments for the count operation. + + Returns + ------- + int + Returns number of entities in the collection. + """ + resource = self.load_resource(name) + + return resource.count(**kwargs) + + def drop(self, name: str, **kwargs: dict[str, typing.Any]) -> None: + """ + Drop a collection, index, or partition in the Milvus vector database. + + This method allows you to drop a collection, an index within a collection, + or a specific partition within a collection in the Milvus vector database. + + Parameters + ---------- + name : str + Name of the collection, index, or partition to be dropped. + **kwargs : dict + Additional keyword arguments for specifying the type and partition name (if applicable). + + Notes on Expected Keyword Arguments: + ------------------------------------ + - 'collection' (str, optional): + Specifies the type of collection to drop. Possible values: 'collection' (default), 'index', 'partition'. + + - 'partition_name' (str, optional): + Required when dropping a specific partition within a collection. Specifies the partition name to be dropped. + + - 'field_name' (str, optional): + Required when dropping an index within a collection. Specifies the field name for which the index is created. + + - 'index_name' (str, optional): + Required when dropping an index within a collection. Specifies the name of the index to be dropped. + + Raises + ------ + ValueError + If mandatory arguments are missing or if the provided 'collection' value is invalid. + """ + + logger.debug("Dropping collection: %s, kwargs=%s", name, kwargs) + + if self.has_store_object(name): + resource = kwargs.get("resource", "collection") + if resource == "collection": + self._client.drop_collection(collection_name=name) + elif resource == "partition": + if "partition_name" not in kwargs: + raise ValueError("Mandatory argument 'partition_name' is required when resource='partition'") + partition_name = kwargs["partition_name"] + if self._client.has_partition(collection_name=name, partition_name=partition_name): + # Collection need to be released before dropping the partition. + self._client.release_collection(collection_name=name) + self._client.drop_partition(collection_name=name, partition_name=partition_name) + elif resource == "index": + if "field_name" in kwargs and "index_name" in kwargs: + self._client.drop_index(collection_name=name, + field_name=kwargs["field_name"], + index_name=kwargs["index_name"]) + else: + raise ValueError( + "Mandatory arguments 'field_name' and 'index_name' are required when resource='index'") + + def describe(self, name: str, **kwargs: dict[str, typing.Any]) -> dict: + """ + Describe the collection in the vector database. + + Parameters + ---------- + name : str + Name of the collection. + **kwargs : dict[str, typing.Any] + Additional keyword arguments specific to the Milvus vector database. + + Returns + ------- + dict + Returns collection information. + """ + + resource = self.load_resource(name) + + return resource.describe(**kwargs) + + def release_resource(self, name: str) -> None: + """ + Release a loaded collection from the memory. + + Parameters + ---------- + name : str + Name of the collection to release. + """ + + self._client.release_collection(collection_name=name) + + def close(self) -> None: + """ + Close the connection to the Milvus vector database. + + This method disconnects from the Milvus vector database by removing the connection. + + """ + self._client.close() diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/langchain_llm_client_wrapper.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/langchain_llm_client_wrapper.py new file mode 100644 index 000000000..18589f9b5 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/langchain_llm_client_wrapper.py @@ -0,0 +1,61 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing + +from cyber_dev_day.llm_service import LLMClient + +IMPORT_EXCEPTION = None +IMPORT_ERROR_MESSAGE = ("LangchainLLMClientWrapper require the langchain package to be installed. " + "Install it by running the following command:\n" + "`conda env update --solver=libmamba -n morpheus " + "--file morpheus/conda/environments/examples_cuda-121_arch-x86_64.yaml --prune`") + +try: + from langchain_core.callbacks import AsyncCallbackManagerForLLMRun + from langchain_core.callbacks import CallbackManagerForLLMRun + from langchain_core.language_models.llms import LLM +except ImportError as import_exc: + IMPORT_EXCEPTION = import_exc + + +class LangchainLLMClientWrapper(LLM): + + client: LLMClient + + @property + def _llm_type(self) -> str: + """Return type of llm.""" + return "morpheus" + + def _call( + self, + prompt: str, + stop: typing.Optional[list[str]] = None, + run_manager: typing.Optional[CallbackManagerForLLMRun] = None, + **kwargs: typing.Any, + ) -> str: + """Run the LLM on the given prompt and input.""" + + return self.client.generate(prompt=prompt, stop=stop) + + async def _acall( + self, + prompt: str, + stop: typing.Optional[list[str]] = None, + run_manager: typing.Optional[AsyncCallbackManagerForLLMRun] = None, + **kwargs: typing.Any, + ) -> str: + """Run the LLM on the given prompt and input.""" + return await self.client.generate_async(prompt=prompt, stop=stop) diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/llm_service.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/llm_service.py new file mode 100644 index 000000000..7777d7ea0 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/llm_service.py @@ -0,0 +1,186 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import importlib +import logging +import typing +from abc import ABC +from abc import abstractmethod + +logger = logging.getLogger(__name__) + + +class LLMClient(ABC): + """ + Abstract interface for clients which are able to interact with LLM models. Concrete implementations of this class + will have an associated implementation of `LLMService` which is able to construct instances of this class. + """ + + @abstractmethod + def get_input_names(self) -> list[str]: + """ + Returns the names of the inputs to the model. + """ + pass + + @abstractmethod + def generate(self, **input_dict) -> str: + """ + Issue a request to generate a response based on a given prompt. + + Parameters + ---------- + input_dict : dict + Input containing prompt data. + """ + pass + + @abstractmethod + async def generate_async(self, **input_dict) -> str: + """ + Issue an asynchronous request to generate a response based on a given prompt. + + Parameters + ---------- + input_dict : dict + Input containing prompt data. + """ + pass + + @typing.overload + @abstractmethod + def generate_batch(self, + inputs: dict[str, list], + return_exceptions: typing.Literal[True] = True) -> list[str | BaseException]: + ... + + @typing.overload + @abstractmethod + def generate_batch(self, inputs: dict[str, list], return_exceptions: typing.Literal[False] = False) -> list[str]: + ... + + @abstractmethod + def generate_batch(self, inputs: dict[str, list], return_exceptions=False) -> list[str] | list[str | BaseException]: + """ + Issue a request to generate a list of responses based on a list of prompts. + + Parameters + ---------- + inputs : dict + Inputs containing prompt data. + return_exceptions : bool + Whether to return exceptions in the output list or raise them immediately. + """ + pass + + @typing.overload + @abstractmethod + async def generate_batch_async(self, + inputs: dict[str, list], + return_exceptions: typing.Literal[True] = True) -> list[str | BaseException]: + ... + + @typing.overload + @abstractmethod + async def generate_batch_async(self, + inputs: dict[str, list], + return_exceptions: typing.Literal[False] = False) -> list[str]: + ... + + @abstractmethod + async def generate_batch_async(self, + inputs: dict[str, list], + return_exceptions=False) -> list[str] | list[str | BaseException]: + """ + Issue an asynchronous request to generate a list of responses based on a list of prompts. + + Parameters + ---------- + inputs : dict + Inputs containing prompt data. + return_exceptions : bool + Whether to return exceptions in the output list or raise them immediately. + """ + pass + + +class LLMService(ABC): + """ + Abstract interface for services which are able to construct clients for interacting with LLM models. + """ + + @abstractmethod + def get_client(self, *, model_name: str, **model_kwargs) -> LLMClient: + """ + Returns a client for interacting with a specific model. + + Parameters + ---------- + model_name : str + The name of the model to create a client for. + + model_kwargs : dict[str, typing.Any] + Additional keyword arguments to pass to the model. + """ + pass + + @typing.overload + @staticmethod + def create(service_type: typing.Literal["nemo"], *service_args, + **service_kwargs) -> "morpheus.llm.services.nemo_llm_service.NeMoLLMService": + pass + + @typing.overload + @staticmethod + def create(service_type: typing.Literal["openai"], *service_args, + **service_kwargs) -> "morpheus.llm.services.nemo_llm_service.OpenAILLMService": + pass + + @typing.overload + @staticmethod + def create(service_type: str, *service_args, **service_kwargs) -> "LLMService": + pass + + @staticmethod + def create(service_type: str | typing.Literal["nemo"] | typing.Literal["openai"], *service_args, **service_kwargs): + """ + Returns a service for interacting with LLM models. + + Parameters + ---------- + service_type : str + The type of the service to create + + service_kwargs : dict[str, typing.Any] + Additional keyword arguments to pass to the service. + """ + module_name = f"cyber_dev_day.{service_type.lower()}_llm_service" + module = importlib.import_module(module_name) + + # Get all of the classes in the module to find the correct service class + mod_classes = dict([(name, cls) for name, cls in module.__dict__.items() if isinstance(cls, type)]) + + class_name_lower = f"{service_type}LLMService".lower() + + # Find case-insensitive match for the class name + matching_classes = [name for name in mod_classes if name.lower() == class_name_lower] + + assert len(matching_classes) == 1, f"Expected to find exactly one class with name {class_name_lower} in module {module_name}, but found {matching_classes}" + + # Create the class + class_ = getattr(module, matching_classes[0]) + + instance = class_(*service_args, **service_kwargs) + + return instance diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/nim_llm_service.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/nim_llm_service.py new file mode 100644 index 000000000..621befbef --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/nim_llm_service.py @@ -0,0 +1,165 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio +import copy +import logging +import os +import time +import typing +from contextlib import contextmanager +from textwrap import dedent +import re + +import appdirs + +from cyber_dev_day.llm_service import LLMClient +from cyber_dev_day.llm_service import LLMService +from cyber_dev_day.openai_chat_service import OpenAIChatService, OpenAIChatClient + +logger = logging.getLogger(__name__) + +IMPORT_EXCEPTION = None +IMPORT_ERROR_MESSAGE = ("OpenAIChatService & OpenAIChatClient require the openai package to be installed. " + "Install it by running the following command:\n" + "`conda env update --solver=libmamba -n morpheus " + "--file conda/environments/dev_cuda-121_arch-x86_64.yaml --prune`") + +try: + import openai + import openai.types.chat + import openai.types.chat.chat_completion +except ImportError as import_exc: + IMPORT_EXCEPTION = import_exc + + +class NIMChatClient(OpenAIChatClient): + """ + Client for interacting with a specific NVIDIA Inference Microservice chat model. This class should be constructed with the + `NIMLLMService.get_client` method. + + Parameters + ---------- + model_name : str + The name of the model to interact with. + + base_url: str + The URI at which the NIM can be reached. + + set_assistant: bool, optional default=False + When `True`, a second input field named `assistant` will be used to proide additional context to the model. + + max_retries: int, optional default=10 + The maximum number of retries to attempt when making a request to the OpenAI API. + + model_kwargs : dict[str, typing.Any] + Additional keyword arguments to pass to the model when generating text. + """ + + _prompt_key: str = "prompt" + _assistant_key: str = "assistant" + + def __init__(self, + parent: "NIMChatService", + *, + model_name: str, + base_url: str, + set_assistant: bool = False, + max_retries: int = 10, + **model_kwargs) -> None: + if IMPORT_EXCEPTION is not None: + raise ImportError(IMPORT_ERROR_MESSAGE) from IMPORT_EXCEPTION + + super().__init__( + parent=parent, + model_name=model_name, + set_assistant=set_assistant, + max_retries=max_retries, + **model_kwargs + ) + + self._base_url = base_url + + # Create the client objects for both sync and async + self._client = openai.OpenAI(base_url = self._base_url, max_retries=max_retries) + self._client_async = openai.AsyncOpenAI(base_url = self._base_url, max_retries=max_retries) + + + +class NIMLLMService(OpenAIChatService): + """ + A service for interacting with NIM Chat models, this class should be used to create clients. + """ + + def __init__(self, *, default_model_kwargs: dict = None) -> None: + """ + Creates a service for interacting with OpenAI Chat models, this class should be used to create clients. + + Parameters + ---------- + default_model_kwargs : dict, optional + Default arguments to use when creating a client via the `get_client` function. Any argument specified here + will automatically be used when calling `get_client`. Arguments specified in the `get_client` function will + overwrite default values specified here. This is useful to set model arguments before creating multiple + clients. By default None + + Raises + ------ + ImportError + If the `openai` library is not found in the python environment. + """ + if IMPORT_EXCEPTION is not None: + raise ImportError(IMPORT_ERROR_MESSAGE) from IMPORT_EXCEPTION + + super().__init__() + + self._default_model_kwargs = default_model_kwargs or {} + + + def get_client(self, + *, + model_name: str, + base_url: str, + set_assistant: bool = False, + max_retries: int = 10, + **model_kwargs) -> NIMChatClient: + """ + Returns a client for interacting with a specific model. This method is the preferred way to create a client. + + Parameters + ---------- + model_name : str + The name of the model to create a client for. + + base_url: str + The URI at which the NIM can be reached. + + set_assistant: bool, optional default=False + When `True`, a second input field named `assistant` will be used to proide additional context to the model. + + max_retries: int, optional default=10 + The maximum number of retries to attempt when making a request to the OpenAI API. + + model_kwargs : dict[str, typing.Any] + Additional keyword arguments to pass to the model when generating text. Arguments specified here will + overwrite the `default_model_kwargs` set in the service constructor + """ + + final_model_kwargs = {**self._default_model_kwargs, **model_kwargs} + + return NIMChatClient(self, + model_name=model_name, + base_url=base_url, + set_assistant=set_assistant, + max_retries=max_retries, + **final_model_kwargs) \ No newline at end of file diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/openai_chat_service.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/openai_chat_service.py new file mode 100644 index 000000000..376a67462 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/openai_chat_service.py @@ -0,0 +1,397 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio +import copy +import logging +import os +import time +import typing +from contextlib import contextmanager +from textwrap import dedent + +import appdirs + +from cyber_dev_day.llm_service import LLMClient +from cyber_dev_day.llm_service import LLMService + +logger = logging.getLogger(__name__) + +IMPORT_EXCEPTION = None +IMPORT_ERROR_MESSAGE = ("OpenAIChatService & OpenAIChatClient require the openai package to be installed. " + "Install it by running the following command:\n" + "`conda env update --solver=libmamba -n morpheus " + "--file conda/environments/dev_cuda-121_arch-x86_64.yaml --prune`") + +try: + import openai + import openai.types.chat + import openai.types.chat.chat_completion +except ImportError as import_exc: + IMPORT_EXCEPTION = import_exc + + +class _ApiLogger: + """ + Simple class that allows passing back and forth the inputs and outputs of an API call via a context manager. + """ + + log_template: typing.ClassVar[str] = dedent(""" + ============= MESSAGE %d START ============== + --- Input --- + %s + --- Output --- (%f ms) + %s + ============= MESSAGE %d END ============== + """).strip("\n") + + def __init__(self, *, message_id: int, inputs: typing.Any) -> None: + + self.message_id = message_id + self.inputs = inputs + self.outputs = None + + def set_output(self, output: typing.Any) -> None: + self.outputs = output + + +class OpenAIChatClient(LLMClient): + """ + Client for interacting with a specific OpenAI chat model. This class should be constructed with the + `OpenAIChatService.get_client` method. + + Parameters + ---------- + model_name : str + The name of the model to interact with. + + set_assistant: bool, optional default=False + When `True`, a second input field named `assistant` will be used to proide additional context to the model. + + max_retries: int, optional default=10 + The maximum number of retries to attempt when making a request to the OpenAI API. + + model_kwargs : dict[str, typing.Any] + Additional keyword arguments to pass to the model when generating text. + """ + + _prompt_key: str = "prompt" + _assistant_key: str = "assistant" + + def __init__(self, + parent: "OpenAIChatService", + *, + model_name: str, + set_assistant: bool = False, + max_retries: int = 10, + **model_kwargs) -> None: + if IMPORT_EXCEPTION is not None: + raise ImportError(IMPORT_ERROR_MESSAGE) from IMPORT_EXCEPTION + + super().__init__() + + assert parent is not None, "Parent service cannot be None." + + self._parent = parent + + self._model_name = model_name + self._set_assistant = set_assistant + self._prompt_key = "prompt" + self._assistant_key = "assistant" + + # Preserve original configuration. + self._model_kwargs = copy.deepcopy(model_kwargs) + + # Create the client objects for both sync and async + self._client = openai.OpenAI(max_retries=max_retries) + self._client_async = openai.AsyncOpenAI(max_retries=max_retries) + + def get_input_names(self) -> list[str]: + input_names = [self._prompt_key] + if self._set_assistant: + input_names.append(self._assistant_key) + + return input_names + + @contextmanager + def _api_logger(self, inputs: typing.Any): + + message_id = self._parent._get_message_id() + start_time = time.time() + + api_logger = _ApiLogger(message_id=message_id, inputs=inputs) + + yield api_logger + + end_time = time.time() + duration_ms = (end_time - start_time) * 1000.0 + + self._parent._logger.info(_ApiLogger.log_template, + message_id, + api_logger.inputs, + duration_ms, + api_logger.outputs, + message_id) + + def _create_messages(self, + prompt: str, + assistant: str = None) -> list["openai.types.chat.ChatCompletionMessageParam"]: + messages: list[openai.types.chat.ChatCompletionMessageParam] = [{"role": "user", "content": prompt}] + + if (self._set_assistant and assistant is not None): + messages.append({"role": "assistant", "content": assistant}) + + return messages + + def _extract_completion(self, completion: "openai.types.chat.chat_completion.ChatCompletion") -> str: + choices = completion.choices + if len(choices) == 0: + raise ValueError("No choices were returned from the model.") + + content = choices[0].message.content + if content is None: + raise ValueError("No content was returned from the model.") + + return content + + @typing.overload + def _generate(self, + prompt: str, + assistant: str = None, + return_exceptions: typing.Literal[True] = True) -> str | BaseException: + ... + + @typing.overload + def _generate(self, prompt: str, assistant: str = None, return_exceptions: typing.Literal[False] = False) -> str: + ... + + def _generate(self, prompt: str, assistant: str = None, return_exceptions: bool = False): + + try: + messages = self._create_messages(prompt, assistant) + + output: openai.types.chat.chat_completion.ChatCompletion = self._client.chat.completions.create( + model=self._model_name, messages=messages, **self._model_kwargs) + + return self._extract_completion(output) + except BaseException as e: + + if return_exceptions: + return e + + raise + + def generate(self, **input_dict) -> str: + """ + Issue a request to generate a response based on a given prompt. + + Parameters + ---------- + input_dict : dict + Input containing prompt data. + """ + return self._generate(input_dict[self._prompt_key], + input_dict.get(self._assistant_key), + return_exceptions=False) + + async def _generate_async(self, prompt: str, assistant: str = None) -> str: + + messages = self._create_messages(prompt, assistant) + + with self._api_logger(inputs=messages) as msg_logger: + + try: + output = await self._client_async.chat.completions.create(model=self._model_name, + messages=messages, + **self._model_kwargs) + except Exception as exc: + self._parent._logger.error("Error generating completion: %s", exc) + raise + + msg_logger.set_output(output) + + return self._extract_completion(output) + + async def generate_async(self, **input_dict) -> str: + """ + Issue an asynchronous request to generate a response based on a given prompt. + + Parameters + ---------- + input_dict : dict + Input containing prompt data. + """ + return await self._generate_async(input_dict[self._prompt_key], input_dict.get(self._assistant_key)) + + @typing.overload + def generate_batch(self, + inputs: dict[str, list], + return_exceptions: typing.Literal[True] = True, **kwargs) -> list[str | BaseException]: + ... + + @typing.overload + def generate_batch(self, inputs: dict[str, list], return_exceptions: typing.Literal[False] = False, **kwargs) -> list[str]: + ... + + def generate_batch(self, inputs: dict[str, list], return_exceptions=False, **kwargs) -> list[str] | list[str | BaseException]: + """ + Issue a request to generate a list of responses based on a list of prompts. + + Parameters + ---------- + inputs : dict + Inputs containing prompt data. + return_exceptions : bool + Whether to return exceptions in the output list or raise them immediately. + """ + prompts = inputs[self._prompt_key] + assistants = None + if (self._set_assistant): + assistants = inputs[self._assistant_key] + if len(prompts) != len(assistants): + raise ValueError("The number of prompts and assistants must be equal.") + + results = [] + for (i, prompt) in enumerate(prompts): + assistant = assistants[i] if assistants is not None else None + if (return_exceptions): + results.append(self._generate(prompt, assistant, return_exceptions=True, **kwargs)) + else: + results.append(self._generate(prompt, assistant, return_exceptions=False, **kwargs)) + + return results + + @typing.overload + async def generate_batch_async(self, + inputs: dict[str, list], + return_exceptions: typing.Literal[True] = True, **kwargs) -> list[str | BaseException]: + ... + + @typing.overload + async def generate_batch_async(self, + inputs: dict[str, list], + return_exceptions: typing.Literal[False] = False, **kwargs) -> list[str]: + ... + + async def generate_batch_async(self, + inputs: dict[str, list], + return_exceptions=False, **kwargs) -> list[str] | list[str | BaseException]: + """ + Issue an asynchronous request to generate a list of responses based on a list of prompts. + + Parameters + ---------- + inputs : dict + Inputs containing prompt data. + return_exceptions : bool + Whether to return exceptions in the output list or raise them immediately. + """ + prompts = inputs[self._prompt_key] + assistants = None + if (self._set_assistant): + assistants = inputs[self._assistant_key] + if len(prompts) != len(assistants): + raise ValueError("The number of prompts and assistants must be equal.") + + coros = [] + for (i, prompt) in enumerate(prompts): + assistant = assistants[i] if assistants is not None else None + coros.append(self._generate_async(prompt, assistant, **kwargs)) + + return await asyncio.gather(*coros, return_exceptions=return_exceptions, **kwargs) + + +class OpenAIChatService(LLMService): + """ + A service for interacting with OpenAI Chat models, this class should be used to create clients. + """ + + def __init__(self, *, default_model_kwargs: dict = None) -> None: + """ + Creates a service for interacting with OpenAI Chat models, this class should be used to create clients. + + Parameters + ---------- + default_model_kwargs : dict, optional + Default arguments to use when creating a client via the `get_client` function. Any argument specified here + will automatically be used when calling `get_client`. Arguments specified in the `get_client` function will + overwrite default values specified here. This is useful to set model arguments before creating multiple + clients. By default None + + Raises + ------ + ImportError + If the `openai` library is not found in the python environment. + """ + if IMPORT_EXCEPTION is not None: + raise ImportError(IMPORT_ERROR_MESSAGE) from IMPORT_EXCEPTION + + super().__init__() + + self._default_model_kwargs = default_model_kwargs or {} + + self._logger = logging.getLogger(f"{__package__}.{OpenAIChatService.__name__}") + + # Dont propagate up to the default logger. Just log to file + self._logger.propagate = False + + log_file = os.path.join(appdirs.user_log_dir(appauthor="NVIDIA", appname="morpheus"), "openai.log") + + # Add a file handler + file_handler = logging.FileHandler(log_file) + + self._logger.addHandler(file_handler) + self._logger.setLevel(logging.INFO) + + self._logger.info("OpenAI Chat Service started.") + + self._message_count = 0 + + def _get_message_id(self): + + self._message_count += 1 + + return self._message_count + + def get_client(self, + *, + model_name: str, + set_assistant: bool = False, + max_retries: int = 10, + **model_kwargs) -> OpenAIChatClient: + """ + Returns a client for interacting with a specific model. This method is the preferred way to create a client. + + Parameters + ---------- + model_name : str + The name of the model to create a client for. + + set_assistant: bool, optional default=False + When `True`, a second input field named `assistant` will be used to proide additional context to the model. + + max_retries: int, optional default=10 + The maximum number of retries to attempt when making a request to the OpenAI API. + + model_kwargs : dict[str, typing.Any] + Additional keyword arguments to pass to the model when generating text. Arguments specified here will + overwrite the `default_model_kwargs` set in the service constructor + """ + + final_model_kwargs = {**self._default_model_kwargs, **model_kwargs} + + return OpenAIChatClient(self, + model_name=model_name, + set_assistant=set_assistant, + max_retries=max_retries, + **final_model_kwargs) diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/pipeline.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/pipeline.py new file mode 100644 index 000000000..38d71ac82 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/pipeline.py @@ -0,0 +1,137 @@ +# Copyright (c) 2023-2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import time + +import cudf + +from morpheus.config import Config +from morpheus.config import PipelineModes +from morpheus.messages import ControlMessage +from morpheus.pipeline.linear_pipeline import LinearPipeline +from morpheus.stages.input.in_memory_source_stage import InMemorySourceStage +from morpheus.stages.llm.llm_engine_stage import LLMEngineStage +from morpheus.stages.output.in_memory_sink_stage import InMemorySinkStage +from morpheus.stages.preprocess.deserialize_stage import DeserializeStage +from morpheus.utils.concat_df import concat_dataframes + +from .config import EngineAgentConfig +from .config import EngineChecklistConfig +from .config import EngineCodeRepoConfig +from .config import EngineConfig +from .config import EngineSBOMConfig +from .config import NeMoLLMModelConfig +from .config import NeMoLLMServiceConfig +from .config import NVFoundationLLMModelConfig +from .config import NVFoundationLLMServiceConfig +from .pipeline_utils import build_cve_llm_engine + +logger = logging.getLogger(__name__) + + +def pipeline( + num_threads: int, + pipeline_batch_size, + model_max_batch_size, + model_name, + repeat_count, +) -> float: + + nemo_service_config = NeMoLLMServiceConfig() + nvfoundation_service_config = NVFoundationLLMServiceConfig() + + engine_config = EngineConfig( + checklist=EngineChecklistConfig(model=NeMoLLMModelConfig(service=nemo_service_config, + model_name="gpt-43b-002"), ), + agent=EngineAgentConfig( + model=NVFoundationLLMModelConfig(service=nvfoundation_service_config, model_name="mixtral_8x7b"), + sbom=EngineSBOMConfig(data_file=""), + code_repo=EngineCodeRepoConfig( + faiss_dir="/home/mdemoret/Repos/morpheus/morpheus-dev2/.tmp/Sherlock/NSPECT-V1TL-NPZI_code_faiss", + embedding_model_name="Xenova/text-embedding-ada-002"), + ), + ) + + engine_config = EngineConfig.model_validate({ + 'checklist': { + 'model': { + 'service': { + 'type': 'nemo', 'api_key': None, 'org_id': None + }, + 'model_name': 'gpt-43b-002', + 'customization_id': None, + 'temperature': 0.0, + 'tokens_to_generate': 300 + } + }, + 'agent': { + 'model': { + 'service': { + 'type': 'nvfoundation', 'api_key': None + }, 'model_name': 'mixtral_8x7b', 'temperature': 0.0 + }, + 'sbom': { + 'data_file': '' + }, + 'code_repo': { + 'faiss_dir': '/home/mdemoret/Repos/morpheus/morpheus-dev2/.tmp/Sherlock/NSPECT-V1TL-NPZI_code_faiss', + 'embedding_model_name': 'Xenova/text-embedding-ada-002' + } + } + }) + + logger.info("Using Engine Config: %s", engine_config.model_dump_json(indent=2)) + + config = Config() + config.mode = PipelineModes.OTHER + + # Below properties are specified by the command line + config.num_threads = num_threads + config.pipeline_batch_size = pipeline_batch_size + config.model_max_batch_size = model_max_batch_size + config.mode = PipelineModes.NLP + config.edge_buffer_size = 128 + + source_dfs = [ + cudf.DataFrame({ + "cve_info": [ + "An issue was discovered in the Linux kernel through 6.0.9. drivers/media/dvb-core/dvbdev.c has a use-after-free, related to dvb_register_device dynamically allocating fops." + ] + }) + ] + + completion_task = {"task_type": "completion", "task_dict": {"input_keys": ["cve_info"], }} + + pipe = LinearPipeline(config) + + pipe.set_source(InMemorySourceStage(config, dataframes=source_dfs, repeat=repeat_count)) + + pipe.add_stage( + DeserializeStage(config, message_type=ControlMessage, task_type="llm_engine", task_payload=completion_task)) + + pipe.add_stage(LLMEngineStage(config, engine=build_cve_llm_engine(engine_config))) + + sink = pipe.add_stage(InMemorySinkStage(config)) + + start_time = time.time() + + pipe.run() + + messages = sink.get_messages() + responses = concat_dataframes(messages) + + logger.info("Pipeline complete. Received %s responses:\n%s", len(messages), responses['response']) + + return start_time diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/pipeline_utils.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/pipeline_utils.py new file mode 100644 index 000000000..660d4e618 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/pipeline_utils.py @@ -0,0 +1,262 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from langchain.agents import AgentType +from langchain.agents import Tool +from langchain.agents import initialize_agent +from langchain.agents.agent import AgentExecutor +from langchain.chains import RetrievalQA +from langchain.embeddings.huggingface import HuggingFaceEmbeddings +from langchain.vectorstores.faiss import FAISS + +from morpheus.llm import LLMEngine +from morpheus.llm.nodes.extracter_node import ExtracterNode +from morpheus.llm.nodes.langchain_agent_node import LangChainAgentNode +from cyber_dev_day.llm_service import LLMService +from cyber_dev_day.langchain_llm_client_wrapper import LangchainLLMClientWrapper +from morpheus.llm.task_handlers.simple_task_handler import SimpleTaskHandler + +from .checklist_node import CVEChecklistNode +from .config import EngineAgentConfig +from .config import EngineConfig +from .tools import SBOMChecker + +logger = logging.getLogger(__name__) + + +def build_agent_executor(config: EngineAgentConfig, handle_parsing_errors=False) -> AgentExecutor: + llm_service = LLMService.create(config.model.service.type, **config.model.service.model_dump(exclude={"type"})) + + llm_client = llm_service.get_client(**config.model.model_dump(exclude={"service"})) + + # Wrap the Morpheus client in a LangChain compatible wrapper + langchain_llm = LangchainLLMClientWrapper(client=llm_client) + + # tools = load_tools(["serpapi", "llm-math"], llm=llm) + tools: list[Tool] = [] + + if (config.sbom.data_file is not None): + # Load the SBOM + sbom_checker = SBOMChecker.from_csv(config.sbom.data_file) + + tools.append( + Tool(name="SBOM Package Checker", + func=sbom_checker.sbom_checker, + description=("useful for when you need to check the Docker container's software bill of " + "materials (SBOM) to get whether or not a given library is in the container. " + "Input should be the name of the library or software, and no text following it until a response is returned. " + "If the package is " + "present a version number is returned, otherwise False is returned if the " + "package is not present."))) + + if (config.code_repo.faiss_dir is not None): + embeddings = HuggingFaceEmbeddings(model_name=config.code_repo.embedding_model_name, + model_kwargs={'device': 'cuda'}, + encode_kwargs={'normalize_embeddings': False}) + + # load code vector DB + code_vector_db = FAISS.load_local(folder_path=config.code_repo.faiss_dir, + embeddings=embeddings, + allow_dangerous_deserialization=True) + code_qa_tool = RetrievalQA.from_chain_type(llm=langchain_llm, + chain_type="stuff", + retriever=code_vector_db.as_retriever()) + tools.append( + Tool(name="Docker Container Code QA System", + func=code_qa_tool.run, + description=("useful for when you need to review code to check for an import or function usage in " + "the Docker container. Input should be a question or the actual code. "))) + + sys_prompt = ("You are a very powerful assistant who helps investigate Docker containers " + " given a checklist of investigation items. Your role is to walk through a provided checklist and answer each item in the checklist. " + " Do not investigate additional information per checklist item, just answer the checklist. " + " Information about the Docker container under investigation is stored in vector databases available to you via tools. ") + + if handle_parsing_errors: + agent_executor = initialize_agent(tools, + langchain_llm, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=config.verbose, + handle_parsing_errors="Check your output. Make sure you're using the right Action/Action input syntax.") + else: + agent_executor = initialize_agent(tools, + langchain_llm, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=config.verbose) + + agent_executor.agent.llm_chain.prompt.template = ( + sys_prompt + ' ' + agent_executor.agent.llm_chain.prompt.template.replace( + "Answer the following questions as best you can.", + ("If the input is not a question, formulate it into a question first. " + "Include intermediate thought in the final answer.")).replace( + "Use the following format:", + ("Use the following format (start each response with one of the following prefixes): " + "[Question, Thought, Action, Action Input, Final Answer]). " + "If you are making an action, wait for a response to the action input before making an observation. Every response must contain at least one action (and thoughts and observations if you have them), but you cannot have both a final answer and an action in a response. Action input must only contain the exact input, do not provide any text following that in your response. Always end your response with either an action, or a final answer."))) + + return agent_executor + + +def build_cve_llm_engine(config: EngineConfig, handle_parsing_errors=True) -> LLMEngine: + engine = LLMEngine() + + engine.add_node("extracter", node=ExtracterNode()) + + engine.add_node("checklist", inputs=["/extracter"], node=CVEChecklistNode(config=config.checklist)) + + engine.add_node("agent", + inputs=[("/checklist")], + node=LangChainAgentNode(agent_executor=build_agent_executor(config=config.agent, + handle_parsing_errors=handle_parsing_errors))) + + engine.add_task_handler( + inputs=[("/checklist", "checklist"), ("/agent", "response")], + handler=SimpleTaskHandler(output_columns=["checklist", "response"]), + ) + + return engine + + +# Copyright (c) 2024, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from langchain.agents import AgentType +from langchain.agents import Tool +from langchain.agents import initialize_agent +from langchain.agents.agent import AgentExecutor +from langchain.chains import RetrievalQA +from langchain.embeddings.huggingface import HuggingFaceEmbeddings +from langchain.vectorstores.faiss import FAISS + +from morpheus.llm import LLMEngine +from morpheus.llm.nodes.extracter_node import ExtracterNode +from morpheus.llm.nodes.langchain_agent_node import LangChainAgentNode +from cyber_dev_day.llm_service import LLMService +from cyber_dev_day.langchain_llm_client_wrapper import LangchainLLMClientWrapper +from morpheus.llm.task_handlers.simple_task_handler import SimpleTaskHandler + +from .checklist_node import CVEChecklistNode +from .config import EngineAgentConfig +from .config import EngineConfig +from .tools import SBOMChecker + +logger = logging.getLogger(__name__) + + +def build_agent_executor(config: EngineAgentConfig, handle_parsing_errors=False) -> AgentExecutor: + llm_service = LLMService.create(config.model.service.type, **config.model.service.model_dump(exclude={"type"})) + + llm_client = llm_service.get_client(**config.model.model_dump(exclude={"service"})) + + # Wrap the Morpheus client in a LangChain compatible wrapper + langchain_llm = LangchainLLMClientWrapper(client=llm_client) + + # tools = load_tools(["serpapi", "llm-math"], llm=llm) + tools: list[Tool] = [] + + if (config.sbom.data_file is not None): + # Load the SBOM + sbom_checker = SBOMChecker.from_csv(config.sbom.data_file) + + tools.append( + Tool(name="SBOM Package Checker", + func=sbom_checker.sbom_checker, + description=("useful for when you need to check the Docker container's software bill of " + "materials (SBOM) to get whether or not a given library is in the container. " + "Input should be the name of the library or software, and no text following it until a response is returned. " + "If the package is " + "present a version number is returned, otherwise False is returned if the " + "package is not present."))) + + if (config.code_repo.faiss_dir is not None): + embeddings = HuggingFaceEmbeddings(model_name=config.code_repo.embedding_model_name, + model_kwargs={'device': 'cuda'}, + encode_kwargs={'normalize_embeddings': False}) + + # load code vector DB + code_vector_db = FAISS.load_local(folder_path=config.code_repo.faiss_dir, + embeddings=embeddings, + allow_dangerous_deserialization=True) + code_qa_tool = RetrievalQA.from_chain_type(llm=langchain_llm, + chain_type="stuff", + retriever=code_vector_db.as_retriever()) + tools.append( + Tool(name="Docker Container Code QA System", + func=code_qa_tool.run, + description=("useful for when you need to review code to check for an import or function usage in " + "the Docker container. Input should be a question or the actual code. "))) + + sys_prompt = ("You are a very powerful assistant who helps investigate Docker containers " + " given a checklist of investigation items. Your role is to walk through a provided checklist and answer each item in the checklist. " + " Do not investigate additional information per checklist item, just answer the checklist. " + " Information about the Docker container under investigation is stored in vector databases available to you via tools. ") + + if handle_parsing_errors: + agent_executor = initialize_agent(tools, + langchain_llm, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=config.verbose, + handle_parsing_errors="Check your output. Make sure you're using the right Action/Action input syntax.") + else: + agent_executor = initialize_agent(tools, + langchain_llm, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=config.verbose) + + agent_executor.agent.llm_chain.prompt.template = ( + sys_prompt + ' ' + agent_executor.agent.llm_chain.prompt.template.replace( + "Answer the following questions as best you can.", + ("If the input is not a question, formulate it into a question first. " + "Include intermediate thought in the final answer.")).replace( + "Use the following format:", + ("Use the following format (start each response with one of the following prefixes): " + "[Question, Thought, Action, Action Input, Final Answer]). " + "If you are making an action, wait for a response to the action input before making an observation. Every response must contain at least one action (and thoughts and observations if you have them), but you cannot have both a final answer and an action in a response. Action input must only contain the exact input, do not provide any text following that in your response. Always end your response with either an action, or a final answer."))) + + return agent_executor + + +def build_cve_llm_engine(config: EngineConfig, handle_parsing_errors=True) -> LLMEngine: + engine = LLMEngine() + + engine.add_node("extracter", node=ExtracterNode()) + + engine.add_node("checklist", inputs=["/extracter"], node=CVEChecklistNode(config=config.checklist)) + + engine.add_node("agent", + inputs=[("/checklist")], + node=LangChainAgentNode(agent_executor=build_agent_executor(config=config.agent, + handle_parsing_errors=handle_parsing_errors))) + + engine.add_task_handler( + inputs=[("/checklist", "checklist"), ("/agent", "response")], + handler=SimpleTaskHandler(output_columns=["checklist", "response"]), + ) + + return engine diff --git a/experimental/event-driven-rag-cve-analysis/cyber_dev_day/tools.py b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/tools.py new file mode 100644 index 000000000..f12442272 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/cyber_dev_day/tools.py @@ -0,0 +1,191 @@ +# Copyright (c) 2023, NVIDIA CORPORATION. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import warnings +from textwrap import dedent + +from packaging.version import InvalidVersion +from packaging.version import parse as parse_version + +logger = logging.getLogger(__name__) + + +def range_version_comparator(software_version: str, vulnerability_lower_range: str, vulnerability_upper_range: str): + """ + Compare a software's version to a range of vulnerable versions to determine vulnerability. + + Parameters + ---------- + software_version : str + The version of the software currently in use. + vulnerability_lower_range : str + The lower bound of the vulnerable version range. + vulnerability_upper_range : str + The upper bound of the vulnerable version range. + + Returns + ------- + bool + Returns True if the software version is within the range of vulnerable versions, + indicating potential vulnerability. + + Raises + ------ + InvalidVersion + If the version strings are not in a valid format, a warning is issued and alphabetic + comparison is used instead. + + Notes + ----- + This function assumes that the software is vulnerable if its version falls inclusively + between the lower and upper bounds of the vulnerability range. It uses the `parse_version` + function to interpret the versions and compares them accordingly. If `parse_version` fails, + Debian version parsing is attempted. Finally, if both of these fail, it falls + back to a simple string comparison. + """ + try: + sv = parse_version(str(software_version)) + lvv = parse_version(str(vulnerability_lower_range)) + uvv = parse_version(str(vulnerability_upper_range)) + return sv <= uvv and sv >= lvv + except InvalidVersion: + #Failed PEP440 versioning; moving on to Debian + pass + + try: + return Dpkg.compare_versions(str(software_version), + str(vulnerability_lower_range)) != -1 and Dpkg.compare_versions( + str(software_version), str(vulnerability_upper_range)) != 1 + except DpkgVersionError: + warnings.warn('Unable to parse provided versions. Using alpha sorting.', stacklevel=2) + # Fallback to alphabetic comparison if version parsing fails + return str(software_version) <= str(vulnerability_upper_range) and str(software_version) >= str( + vulnerability_lower_range) + + +def single_version_comparator(software_version: str, vulnerability_version: str): + """ + Compare a software's version to a known vulnerable version. + + Parameters + ---------- + software_version : str + The version of the software currently in use. + vulnerability_version : str + The version of the software that is known to be vulnerable. + + Returns + ------- + bool + Returns True if the software version is less than or equal to the vulnerability version, + indicating potential vulnerability. + + Raises + ------ + InvalidVersion + If the version strings are not in a valid format, a warning is issued and alphabetic + comparison is used instead. + """ + try: + sv = parse_version(str(software_version)) + vv = parse_version(str(vulnerability_version)) + return sv <= vv + except InvalidVersion: + #Failed PEP440 versioning; moving on to Debian + pass + try: + return Dpkg.compare_versions(str(software_version), str(vulnerability_version)) != 1 + except DpkgVersionError: + warnings.warn('Unable to parse provided versions. Using alpha sorting.', stacklevel=2) + return str(software_version) <= str(vulnerability_version) + + +def version_comparison(software_version: str): + """ + Compare a software's version to multiple known vulnerable versions. + + Parameters + ---------- + software_version : str + A string containing the software version to compare, and the vulnerable versions, + separated by commas. A single vulnerable version, a vulnerable range (two versions), + or multiple specific vulnerable versions can be provided. + + Returns + ------- + bool or str + Returns True if the software version matches any of the vulnerable versions, + or is within the vulnerable range. Returns a string message if the input doesn't + contain enough information for a comparison. + + Notes + ----- + This function can compare against a single vulnerable version, a range of versions, + or a list of specific versions. It uses the `single_version_comparator` for single comparisons, + and `range_version_comparator` for range comparisons. + """ + v = software_version.split(',') + if len(v) == 2: + return single_version_comparator(v[0], v[1]) + elif len(v) == 3: + return range_version_comparator(v[0], v[1], v[2]) + elif len(v) > 3: + return any([v[0] == v_ for v_ in v[1:]]) + else: + return "Couldn't able compare the software version, not enough input" + + +class SBOMChecker: + + tool_description = dedent(""" + Useful for when you need to check the Docker container's software bill of + materials (SBOM) to get whether or not a given library is in the container. + Input should be the name of the library or software. If the package is + present a version number is returned, otherwise False is returned if the + package is not present. + """).replace("\n", "") + + def __init__(self, sbom_map: dict[str, str]): + + # Convert all keys to lowercase + self.sbom_map = {k.lower().strip(): v for k, v in sbom_map.items()} + + def sbom_checker(self, package_name: str): + "use this tool to check the version of the software package from the SBOM" + "returns the software version if the package is present in the SBOM" + "if the package is not in the SBOM returns False" + + num_substrings = len(package_name.split()) + + if num_substrings > 1: + return f"Could not comple action, try again. Action input must be only the package name. Input should not contain {package_name.split(maxsplit=1)[1:]} or any text after {package_name.split(maxsplit=1)[0]}" + + cleaned_package = package_name.lower().strip() + + return self.sbom_map.get(cleaned_package, f"The package '{cleaned_package}' was not found in the SBOM") + + @staticmethod + def from_csv(file_path: str) -> "SBOMChecker": + """ + Use this tool to load the SBOM from a CSV file returns an instance of the SBOMChecker class + """ + try: + import pandas as pd + sbom = pd.read_csv(file_path) + sbom_map = dict(zip(sbom['package'].str.lower(), sbom['version'])) + return SBOMChecker(sbom_map) + except Exception as e: + logger.error("Error loading SBOM from CSV file: %s. Error: %s", file_path, str(e), exc_info=True) + raise e diff --git a/experimental/event-driven-rag-cve-analysis/data/morpheus_24.03-runtime_sbom.csv b/experimental/event-driven-rag-cve-analysis/data/morpheus_24.03-runtime_sbom.csv new file mode 100644 index 000000000..b9c17f7c0 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/data/morpheus_24.03-runtime_sbom.csv @@ -0,0 +1,914 @@ +package,version,license,type,cpes,origin,image_url,platform,created +ca-certificates,20230311ubuntu0.22.04.1,GPL-2 GPL-2+ MPL-2.0,dpkg,"['cpe:2.3:a:ca-certificates:ca-certificates:20230311ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ca-certificates:ca_certificates:20230311ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ca_certificates:ca-certificates:20230311ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ca_certificates:ca_certificates:20230311ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ca:ca-certificates:20230311ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ca:ca_certificates:20230311ubuntu0.22.04.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cpp-11,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:cpp-11:cpp-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:cpp-11:cpp_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:cpp_11:cpp-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:cpp_11:cpp_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:cpp:cpp-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:cpp:cpp_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +curl,7.81.0-1ubuntu1.15,BSD-3-Clause BSD-4-Clause ISC curl other public-domain,dpkg,['cpe:2.3:a:curl:curl:7.81.0-1ubuntu1.15:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +debianutils,5.5-1ubuntu2,GPL-2,dpkg,['cpe:2.3:a:debianutils:debianutils:5.5-1ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +exceptiongroup,1.2.0,Unknown,PYTHON,"['cpe:2.3:a:python-exceptiongroup:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-exceptiongroup:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_exceptiongroup:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_exceptiongroup:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:exceptiongroup:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:exceptiongroup:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-exceptiongroup:exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_exceptiongroup:exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:exceptiongroup:exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:exceptiongroup:1.2.0:*:*:*:*:*:*:*']", >,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +filelock,3.13.1,Unknown,PYTHON,"['cpe:2.3:a:python-filelock:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-filelock:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_filelock:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_filelock:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:filelock:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:filelock:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-filelock:filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_filelock:filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:filelock:filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:filelock:3.13.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sphinxcontrib-jsmath,1.0.1,BSD,PYTHON,"['cpe:2.3:a:python-sphinxcontrib-jsmath:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-jsmath:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_jsmath:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_jsmath:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_project:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_project:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-jsmath:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-jsmath:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_jsmath:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_jsmath:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib-jsmath:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib-jsmath:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib_jsmath:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib_jsmath:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandlproject:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandlproject:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_project:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_project:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_project:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_project:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib-jsmath:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib-jsmath:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib_jsmath:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib_jsmath:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandlproject:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandlproject:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georgproject:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georgproject:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_project:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_project:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg:python-sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg:python_sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georgproject:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georgproject:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg:sphinxcontrib-jsmath:1.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:georg:sphinxcontrib_jsmath:1.0.1:*:*:*:*:*:*:*']",Georg Brandl ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpg-wks-server,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,"['cpe:2.3:a:gpg-wks-server:gpg-wks-server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-wks-server:gpg_wks_server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks_server:gpg-wks-server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks_server:gpg_wks_server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-wks:gpg-wks-server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-wks:gpg_wks_server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks:gpg-wks-server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks:gpg_wks_server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg:gpg-wks-server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg:gpg_wks_server:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpgv,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:gpgv:gpgv:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gzip,1.10-4ubuntu4.1,FSF-manpages GFDL-1.3+-no-invariant GFDL-3 GPL-3 GPL-3+,dpkg,['cpe:2.3:a:gzip:gzip:1.10-4ubuntu4.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +init-system-helpers,1.62,BSD-3-clause GPL-2 GPL-2+,dpkg,"['cpe:2.3:a:init-system-helpers:init-system-helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init-system-helpers:init_system_helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init_system_helpers:init-system-helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init_system_helpers:init_system_helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init-system:init-system-helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init-system:init_system_helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init_system:init-system-helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init_system:init_system_helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init:init-system-helpers:1.62:*:*:*:*:*:*:*', 'cpe:2.3:a:init:init_system_helpers:1.62:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libmount1,2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,['cpe:2.3:a:libmount1:libmount1:2.37.2-4ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +GitPython,3.1.40,BSD,PYTHON,"['cpe:2.3:a:sebastian_thiel\\,_michael_trier_project:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trier_project:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trierproject:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trierproject:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trier_project:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trier:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trier:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trierproject:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel\\,_michael_trier:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python-GitPython:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python-GitPython:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python_GitPython:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python_GitPython:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:GitPython:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:GitPython:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python-GitPython:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python_GitPython:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:GitPython:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:GitPython:3.1.40:*:*:*:*:*:*:*', 'cpe:2.3:a:python:GitPython:3.1.40:*:*:*:*:*:*:*']","Sebastian Thiel, Michael Trier ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libncurses6,6.3-2ubuntu0.1,BSD-3-clause MIT/X11 X11,dpkg,['cpe:2.3:a:libncurses6:libncurses6:6.3-2ubuntu0.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnpth0,1.6-3build2,LGPL-2.1 LGPL-2.1+,dpkg,['cpe:2.3:a:libnpth0:libnpth0:1.6-3build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gnupg2,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:gnupg2:gnupg2:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpg-wks-client,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,"['cpe:2.3:a:gpg-wks-client:gpg-wks-client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-wks-client:gpg_wks_client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks_client:gpg-wks-client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks_client:gpg_wks_client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-wks:gpg-wks-client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-wks:gpg_wks_client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks:gpg-wks-client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_wks:gpg_wks_client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg:gpg-wks-client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg:gpg_wks_client:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +filelock,3.13.1,Unknown,PYTHON,"['cpe:2.3:a:python-filelock:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-filelock:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_filelock:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_filelock:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:filelock:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:filelock:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-filelock:filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_filelock:filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:filelock:filelock:3.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:filelock:3.13.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +prometheus-client,0.19.0,Apache Software License 2.0,PYTHON,"['cpe:2.3:a:python-prometheus-client:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-client:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_client:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_client:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil_project:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil_project:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazilproject:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazilproject:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-client:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-client:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_client:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_client:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-client:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-client:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_client:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_client:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil_project:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil_project:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian-brazil:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian-brazil:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazilproject:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazilproject:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-client:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-client:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_client:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_client:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian-brazil:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian-brazil:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_brazil:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:prometheus_client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:prometheus-client:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:prometheus_client:0.19.0:*:*:*:*:*:*:*']",Brian Brazil ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcc1-0,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:libcc1-0:libcc1-0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libcc1-0:libcc1_0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libcc1_0:libcc1-0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libcc1_0:libcc1_0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libcc1:libcc1-0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libcc1:libcc1_0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gcc,4:11.2.0-1ubuntu1,GPL-2,dpkg,['cpe:2.3:a:gcc:gcc:4\\:11.2.0-1ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gcc-11-base,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:gcc-11-base:gcc-11-base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-11-base:gcc_11_base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_11_base:gcc-11-base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_11_base:gcc_11_base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-11:gcc-11-base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-11:gcc_11_base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_11:gcc-11-base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_11:gcc_11_base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc:gcc-11-base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc:gcc_11_base:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cffi,1.15.1,MIT,PYTHON,"['cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski_project:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski_project:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowskiproject:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowskiproject:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski_project:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowskiproject:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi_project:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi_project:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffiproject:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffiproject:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi_project:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cffi:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cffi:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffiproject:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cffi:python-cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cffi:python_cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cffi:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cffi:1.15.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cffi:cffi:1.15.1:*:*:*:*:*:*:*']","Armin Rigo, Maciej Fijalkowski ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcufft-11-8,10.9.0.58-1,Unknown,dpkg,"['cpe:2.3:a:libcufft-11-8:libcufft-11-8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft-11-8:libcufft_11_8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft_11_8:libcufft-11-8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft_11_8:libcufft_11_8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft-11:libcufft-11-8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft-11:libcufft_11_8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft_11:libcufft-11-8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft_11:libcufft_11_8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft:libcufft-11-8:10.9.0.58-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcufft:libcufft_11_8:10.9.0.58-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcrypt1,1:4.4.27-1,Unknown,dpkg,['cpe:2.3:a:libcrypt1:libcrypt1:1\\:4.4.27-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +openssh-client,1:8.9p1-3ubuntu0.4,BSD-2-clause BSD-3-clause Expat-with-advertising-restriction Mazieres-BSD-style OpenSSH Powell-BSD-style public-domain,dpkg,"['cpe:2.3:a:openssh-client:openssh-client:1\\:8.9p1-3ubuntu0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:openssh-client:openssh_client:1\\:8.9p1-3ubuntu0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:openssh_client:openssh-client:1\\:8.9p1-3ubuntu0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:openssh_client:openssh_client:1\\:8.9p1-3ubuntu0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:openssh:openssh-client:1\\:8.9p1-3ubuntu0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:openssh:openssh_client:1\\:8.9p1-3ubuntu0.4:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libdb5.3,5.3.28+dfsg1-0.8ubuntu3,Unknown,dpkg,['cpe:2.3:a:libdb5.3:libdb5.3:5.3.28\\+dfsg1-0.8ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +binutils,2.38-4ubuntu2.3,GFDL GPL LGPL,dpkg,['cpe:2.3:a:binutils:binutils:2.38-4ubuntu2.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libedit2,3.1-20210910-1build1,BSD-3-clause,dpkg,['cpe:2.3:a:libedit2:libedit2:3.1-20210910-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +perl,5.34.0-3ubuntu1.3,"Artistic Artistic-2 Artistic-dist BSD-3-clause BSD-3-clause-GENERIC BSD-3-clause-with-weird-numbering BSD-4-clause-POWERDOG BZIP DONT-CHANGE-THE-GPL Expat GPL-1 GPL-1+ GPL-2 GPL-2+ GPL-3+-WITH-BISON-EXCEPTION HSIEH-BSD HSIEH-DERIVATIVE LGPL-2.1 REGCOMP REGCOMP, RRA-KEEP-THIS-NOTICE SDBM-PUBLIC-DOMAIN TEXT-TABS Unicode ZLIB",dpkg,['cpe:2.3:a:perl:perl:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +unzip,6.0-26ubuntu3.1,Unknown,dpkg,['cpe:2.3:a:unzip:unzip:6.0-26ubuntu3.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +build-essential,12.9ubuntu3,GPL,dpkg,"['cpe:2.3:a:build-essential:build-essential:12.9ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:build-essential:build_essential:12.9ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:build_essential:build-essential:12.9ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:build_essential:build_essential:12.9ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:build:build-essential:12.9ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:build:build_essential:12.9ubuntu3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +wget,1.21.2-2ubuntu1,GFDL-1.2 GPL-3,dpkg,['cpe:2.3:a:wget:wget:1.21.2-2ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libffi8,3.4.2-4,GPL,dpkg,['cpe:2.3:a:libffi8:libffi8:3.4.2-4:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +xz-utils,5.2.5-2ubuntu1,Autoconf GPL-2 GPL-2+ GPL-3 LGPL-2 LGPL-2.1 LGPL-2.1+ PD PD-debian config-h noderivs permissive-fsf permissive-nowarranty probably-PD,dpkg,"['cpe:2.3:a:xz-utils:xz-utils:5.2.5-2ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:xz-utils:xz_utils:5.2.5-2ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:xz_utils:xz-utils:5.2.5-2ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:xz_utils:xz_utils:5.2.5-2ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:xz:xz-utils:5.2.5-2ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:xz:xz_utils:5.2.5-2ubuntu1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libfido2-1,1.10.0-1,BSD-2-clause ISC public-domain,dpkg,"['cpe:2.3:a:libfido2-1:libfido2-1:1.10.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libfido2-1:libfido2_1:1.10.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libfido2_1:libfido2-1:1.10.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libfido2_1:libfido2_1:1.10.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libfido2:libfido2-1:1.10.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libfido2:libfido2_1:1.10.0-1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +networkx,3.2,Unknown,PYTHON,"['cpe:2.3:a:aric_hagberg_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgmp10,2:6.2.1+dfsg-3ubuntu1,GPL GPL-2 GPL-3 LGPL-3,dpkg,['cpe:2.3:a:libgmp10:libgmp10:2\\:6.2.1\\+dfsg-3ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pytz,2023.3.post1,MIT,PYTHON,"['cpe:2.3:a:stuart_bishop_project:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop_project:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishopproject:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishopproject:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop_project:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_project:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_project:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishopproject:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuartproject:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuartproject:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pytz:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pytz:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pytz:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pytz:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_project:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuartproject:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pytz:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pytz:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytz:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytz:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytz:pytz:2023.3.post1:*:*:*:*:*:*:*']",Stuart Bishop ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +requests,2.31.0,Apache 2.0,PYTHON,"['cpe:2.3:a:kenneth_reitz_project:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me:requests:2.31.0:*:*:*:*:*:*:*']",Kenneth Reitz ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cudf-kafka,23.6.1,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf-kafka:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf-kafka:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf_kafka:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf_kafka:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf-kafka:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf-kafka:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf_kafka:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf_kafka:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf-kafka:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf-kafka:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf_kafka:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf_kafka:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:python-cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:python_cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf-kafka:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf-kafka:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf_kafka:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf_kafka:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cudf_kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:cudf-kafka:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:cudf_kafka:23.6.1:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +confluent-kafka,1.9.2,Unknown,PYTHON,"['cpe:2.3:a:python-confluent-kafka:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent-kafka:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent_kafka:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent_kafka:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc_project:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc_project:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_incproject:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_incproject:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent-kafka:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent-kafka:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_kafka:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_kafka:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent-kafka:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent-kafka:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent_kafka:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent_kafka:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support_project:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support_project:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc_project:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc_project:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:supportproject:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:supportproject:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_incproject:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_incproject:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-confluent:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_confluent:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent-kafka:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent-kafka:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_kafka:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_kafka:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support_project:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support_project:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:supportproject:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:supportproject:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent_inc:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:confluent:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:support:confluent_kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:confluent-kafka:1.9.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:confluent_kafka:1.9.2:*:*:*:*:*:*:*']",Confluent Inc ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libasound2,1.2.6.1-1ubuntu1,LGPL-2.1 LPGL-2.1+,dpkg,['cpe:2.3:a:libasound2:libasound2:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libassuan0,2.5.5-1build1,GAP GAP~FSF GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+,dpkg,['cpe:2.3:a:libassuan0:libassuan0:2.5.5-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +librtmp1,2.4+20151223.gitfa8646d.1-2build4,GPL-2 LGPL-2.1,dpkg,['cpe:2.3:a:librtmp1:librtmp1:2.4\\+20151223.gitfa8646d.1-2build4:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsasl2-2,2.1.27+dfsg2-3ubuntu1.2,BSD-2-clause BSD-2.2-clause BSD-3-clause BSD-3-clause-JANET BSD-3-clause-PADL BSD-4-clause BSD-4-clause-UC FSFULLR GPL-3 GPL-3+ IBM-as-is MIT-CMU MIT-Export MIT-OpenVision OpenLDAP OpenSSL RSA-MD SSLeay,dpkg,"['cpe:2.3:a:libsasl2-2:libsasl2-2:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2-2:libsasl2_2:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2_2:libsasl2-2:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2_2:libsasl2_2:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2:libsasl2-2:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2:libsasl2_2:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libaudit-common,1:3.0.7-1build1,GPL-1 GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libaudit-common:libaudit-common:1\\:3.0.7-1build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libaudit-common:libaudit_common:1\\:3.0.7-1build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libaudit_common:libaudit-common:1\\:3.0.7-1build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libaudit_common:libaudit_common:1\\:3.0.7-1build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libaudit:libaudit-common:1\\:3.0.7-1build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libaudit:libaudit_common:1\\:3.0.7-1build1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +click,8.1.7,BSD-3-Clause,PYTHON,"['cpe:2.3:a:python-click:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-click:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_click:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_click:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:click:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:click:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-click:click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_click:click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:click:click:8.1.7:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libaudit1,1:3.0.7-1build1,GPL-1 GPL-2 LGPL-2.1,dpkg,['cpe:2.3:a:libaudit1:libaudit1:1\\:3.0.7-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +click,8.1.7,BSD-3-Clause,PYTHON,"['cpe:2.3:a:python-click:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-click:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_click:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_click:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:click:python-click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:click:python_click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-click:click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_click:click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:click:8.1.7:*:*:*:*:*:*:*', 'cpe:2.3:a:click:click:8.1.7:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libavahi-client3,0.8-5ubuntu5.2,GPL GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libavahi-client3:libavahi-client3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi-client3:libavahi_client3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_client3:libavahi-client3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_client3:libavahi_client3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi:libavahi-client3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi:libavahi_client3:0.8-5ubuntu5.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsemanage-common,3.3-1build2,GPL LGPL,dpkg,"['cpe:2.3:a:libsemanage-common:libsemanage-common:3.3-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsemanage-common:libsemanage_common:3.3-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsemanage_common:libsemanage-common:3.3-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsemanage_common:libsemanage_common:3.3-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsemanage:libsemanage-common:3.3-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsemanage:libsemanage_common:3.3-1build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsemanage2,3.3-1build2,GPL LGPL,dpkg,['cpe:2.3:a:libsemanage2:libsemanage2:3.3-1build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libbrotli1,1.0.9-2build6,MIT,dpkg,['cpe:2.3:a:libbrotli1:libbrotli1:1.0.9-2build6:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsqlite3-0,3.37.2-2ubuntu0.1,GPL-2 GPL-2+ public-domain,dpkg,"['cpe:2.3:a:libsqlite3-0:libsqlite3-0:3.37.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libsqlite3-0:libsqlite3_0:3.37.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libsqlite3_0:libsqlite3-0:3.37.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libsqlite3_0:libsqlite3_0:3.37.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libsqlite3:libsqlite3-0:3.37.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libsqlite3:libsqlite3_0:3.37.2-2ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libssh-4,0.9.6-2ubuntu0.22.04.1,BSD-2-clause BSD-3-clause LGPL-2.1 LGPL-2.1+~OpenSSL public-domain,dpkg,"['cpe:2.3:a:libssh-4:libssh-4:0.9.6-2ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libssh-4:libssh_4:0.9.6-2ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libssh_4:libssh-4:0.9.6-2ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libssh_4:libssh_4:0.9.6-2ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libssh:libssh-4:0.9.6-2ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libssh:libssh_4:0.9.6-2ubuntu0.22.04.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +attrs,23.1.0,Unknown,PYTHON,"['cpe:2.3:a:hynek_schlawack_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +beautifulsoup4,4.12.2,Unknown,PYTHON,"['cpe:2.3:a:leonard_richardson_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +conda_package_streaming,0.9.0,Unknown,PYTHON,"['cpe:2.3:a:\\""anaconda\\,_inc__\\&_contributors\\""_\\>",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +menuinst,2.0.0,"(c) 2016 Continuum Analytics, Inc. / http://continuum.io + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Continuum Analytics, Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL CONTINUUM ANALYTICS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ",PYTHON,"['cpe:2.3:a:python-menuinst:python-menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-menuinst:python_menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_menuinst:python-menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_menuinst:python_menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:menuinst:python-menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:menuinst:python_menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-menuinst:menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_menuinst:menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:menuinst:menuinst:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:menuinst:2.0.0:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pkgutil_resolve_name,1.3.10,Unknown,PYTHON,"['cpe:2.3:a:python-pkgutil-resolve-name:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve-name:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve-name:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve_name:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve_name:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve_name:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve_name:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve_name:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve_name:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve-name:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve-name:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve-name:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve_name:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve_name:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve_name:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve-name:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve-name:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve_name:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve_name:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve_name:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve_name:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip_project:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip_project:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip_project:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajipproject:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajipproject:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajipproject:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil-resolve:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil_resolve:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil_resolve:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve-name:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve-name:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve_name:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve_name:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip_project:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip_project:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay-sajip:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay-sajip:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay-sajip:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajipproject:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajipproject:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil-resolve:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil_resolve:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkgutil:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkgutil:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay-sajip:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay-sajip:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:vinay_sajip:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:pkgutil:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pkgutil-resolve-name:1.3.10:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pkgutil_resolve_name:1.3.10:*:*:*:*:*:*:*']",Vinay Sajip ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pluggy,1.0.0,MIT,PYTHON,"['cpe:2.3:a:holger_krekel_project:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel_project:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekelproject:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekelproject:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel_project:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_project:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_project:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekelproject:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holgerproject:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holgerproject:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pluggy:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pluggy:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pluggy:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pluggy:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_project:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holgerproject:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pluggy:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pluggy:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pluggy:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pluggy:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pluggy:pluggy:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pluggy:1.0.0:*:*:*:*:*:*:*']",Holger Krekel ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +matplotlib,3.8.2,PSF,PYTHON,"['cpe:2.3:a:john_d__hunter\\,_michael_droettboom_project:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboom_project:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboomproject:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboomproject:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboom_project:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboom:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboom:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboomproject:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:john_d__hunter\\,_michael_droettboom:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_users_project:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_users_project:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_usersproject:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_usersproject:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_users_project:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-matplotlib:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-matplotlib:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_matplotlib:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_matplotlib:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib-users:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib-users:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_users:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_users:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_usersproject:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-matplotlib:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_matplotlib:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib-users:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib_users:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:matplotlib:matplotlib:3.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:matplotlib:3.8.2:*:*:*:*:*:*:*']","John D. Hunter, Michael Droettboom ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +rpds-py,0.13.2,MIT,PYTHON,"['cpe:2.3:a:julian_berman_project:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds_project:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds_project:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpdsproject:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpdsproject:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds-py:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds-py:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds_py:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds_py:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds_project:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds_project:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpdsproject:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpdsproject:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds-py:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds-py:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds_py:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds_py:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds-py:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds-py:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds_py:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds_py:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+rpds:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rpds:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rpds:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds:python-rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds:python_rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds-py:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds-py:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds_py:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds_py:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:rpds_py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds:rpds-py:0.13.2:*:*:*:*:*:*:*', 'cpe:2.3:a:rpds:rpds_py:0.13.2:*:*:*:*:*:*:*']",Julian Berman ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +setuptools,59.8.0,UNKNOWN,PYTHON,"['cpe:2.3:a:python_packaging_authority_project:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority_project:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authorityproject:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authorityproject:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority_project:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authorityproject:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-setuptools:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-setuptools:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_setuptools:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_setuptools:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-setuptools:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_setuptools:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:setuptools:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:setuptools:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:setuptools:setuptools:59.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:setuptools:59.8.0:*:*:*:*:*:*:*']",Python Packaging Authority ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libncursesw6,6.3-2ubuntu0.1,BSD-3-clause MIT/X11 X11,dpkg,['cpe:2.3:a:libncursesw6:libncursesw6:6.3-2ubuntu0.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnsl-dev,1.3.0-2build2,BSD-3-clause GPL-2 GPL-2+-autoconf-exception GPL-2+-libtool-exception GPL-3 GPL-3+-autoconf-exception LGPL-2.1 LGPL-2.1+ MIT permissive-autoconf-m4 permissive-autoconf-m4-no-warranty permissive-configure permissive-fsf permissive-makefile-in,dpkg,"['cpe:2.3:a:libnsl-dev:libnsl-dev:1.3.0-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libnsl-dev:libnsl_dev:1.3.0-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libnsl_dev:libnsl-dev:1.3.0-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libnsl_dev:libnsl_dev:1.3.0-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libnsl:libnsl-dev:1.3.0-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libnsl:libnsl_dev:1.3.0-2build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnspr4,2:4.32-3build1,MPL-2.0,dpkg,['cpe:2.3:a:libnspr4:libnspr4:2\\:4.32-3build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libonig5,6.9.7.1-2build1,BSD-2-clause GPL-2 GPL-2+,dpkg,['cpe:2.3:a:libonig5:libonig5:6.9.7.1-2build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cpp,4:11.2.0-1ubuntu1,GPL-2,dpkg,['cpe:2.3:a:cpp:cpp:4\\:11.2.0-1ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnghttp2-14,1.43.0-1ubuntu0.1,BSD-2-clause Expat GPL-3 GPL-3+ MIT SIL-OFL-1.1 all-permissive,dpkg,"['cpe:2.3:a:libnghttp2-14:libnghttp2-14:1.43.0-1ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libnghttp2-14:libnghttp2_14:1.43.0-1ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libnghttp2_14:libnghttp2-14:1.43.0-1ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libnghttp2_14:libnghttp2_14:1.43.0-1ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libnghttp2:libnghttp2-14:1.43.0-1ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libnghttp2:libnghttp2_14:1.43.0-1ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-toolkit-config-common,12.3.101-1,Unknown,dpkg,"['cpe:2.3:a:cuda-toolkit-config-common:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-config-common:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_config_common:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_config_common:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-config:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-config:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_config:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_config:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-toolkit-config-common:12.3.101-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_toolkit_config_common:12.3.101-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +debconf,1.5.79ubuntu1,BSD-2-clause,dpkg,['cpe:2.3:a:debconf:debconf:1.5.79ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-cudart-11-8,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-cudart-11-8:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-11-8:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_11_8:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_11_8:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-11:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-11:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_11:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_11:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-cudart-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_cudart_11_8:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sqlparse,0.4.4,Unknown,PYTHON,"['cpe:2.3:a:andi_albrecht_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dpkg,1.21.1ubuntu2.2,BSD-2-clause GPL-2 GPL-2+ public-domain-md5 public-domain-s-s-d,dpkg,['cpe:2.3:a:dpkg:dpkg:1.21.1ubuntu2.2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pyarrow-hotfix,0.6,"Apache License, Version 2.0",PYTHON,"['cpe:2.3:a:antoine_pitrou_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gnupg,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:gnupg:gnupg:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sphinxcontrib-qthelp,1.0.6,Unknown,PYTHON,"['cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcurl4,7.81.0-1ubuntu1.15,BSD-3-Clause BSD-4-Clause ISC curl other public-domain,dpkg,['cpe:2.3:a:libcurl4:libcurl4:7.81.0-1ubuntu1.15:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sphinxcontrib-serializinghtml,1.1.9,Unknown,PYTHON,"['cpe:2.3:a:python-sphinxcontrib-serializinghtml:python-sphinxcontrib-serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-serializinghtml:python_sphinxcontrib_serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_serializinghtml:python-sphinxcontrib-serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_serializinghtml:python_sphinxcontrib_serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-serializinghtml:sphinxcontrib-serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-serializinghtml:sphinxcontrib_serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_serializinghtml:sphinxcontrib-serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_serializinghtml:sphinxcontrib_serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib-serializinghtml:python-sphinxcontrib-serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib-serializinghtml:python_sphinxcontrib_serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib_serializinghtml:python-sphinxcontrib-serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:sphinxcontrib_serializinghtml:python_sphinxcontrib_serializinghtml:1.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cattrs,23.2.3,MIT,PYTHON,"['cpe:2.3:a:tin_tvrtkovic_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +certifi,2023.11.17,MPL-2.0,PYTHON,"['cpe:2.3:a:kenneth_reitz_project:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python-certifi:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python-certifi:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python_certifi:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python_certifi:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:certifi:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:certifi:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python-certifi:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python_certifi:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:certifi:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me:certifi:2023.11.17:*:*:*:*:*:*:*']",Kenneth Reitz ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gcc-12-base,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:gcc-12-base:gcc-12-base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-12-base:gcc_12_base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_12_base:gcc-12-base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_12_base:gcc_12_base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-12:gcc-12-base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-12:gcc_12_base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_12:gcc-12-base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_12:gcc_12_base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc:gcc-12-base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc:gcc_12_base:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +chardet,5.2.0,LGPL,PYTHON,"['cpe:2.3:a:mark_pilgrim_project:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrim_project:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrimproject:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrimproject:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-chardet:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-chardet:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_chardet:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_chardet:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrim_project:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrim:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrim:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrimproject:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_project:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_project:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:markproject:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:markproject:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:chardet:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:chardet:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-chardet:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_chardet:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_pilgrim:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark_project:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark:python-chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark:python_chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:markproject:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:chardet:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:chardet:5.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mark:chardet:5.2.0:*:*:*:*:*:*:*']",Mark Pilgrim ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +bash,5.1-6ubuntu1,GPL-3,dpkg,['cpe:2.3:a:bash:bash:5.1-6ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +passwd,1:4.8.1-2ubuntu2.1,GPL-2,dpkg,['cpe:2.3:a:passwd:passwd:1\\:4.8.1-2ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +usrmerge,25ubuntu2,GPL GPL-2,dpkg,['cpe:2.3:a:usrmerge:usrmerge:25ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libexpat1,2.4.7-1ubuntu0.2,MIT,dpkg,['cpe:2.3:a:libexpat1:libexpat1:2.4.7-1ubuntu0.2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +zip,3.0-12build2,Unknown,dpkg,['cpe:2.3:a:zip:zip:3.0-12build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-driver-dev-11-8,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-driver-dev-11-8:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver-dev-11-8:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver_dev_11_8:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver_dev_11_8:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver-dev-11:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver-dev-11:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver_dev_11:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver_dev_11:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver-dev:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver-dev:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver_dev:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver_dev:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-driver:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_driver:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-driver-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_driver_dev_11_8:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +liblz4-1,1.9.3-2build2,BSD-2-clause GPL-2 GPL-2+,dpkg,"['cpe:2.3:a:liblz4-1:liblz4-1:1.9.3-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblz4-1:liblz4_1:1.9.3-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblz4_1:liblz4-1:1.9.3-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblz4_1:liblz4_1:1.9.3-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblz4:liblz4-1:1.9.3-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblz4:liblz4_1:1.9.3-2build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libapt-pkg6.0,2.4.11,GPL-2 GPLv2+,dpkg,"['cpe:2.3:a:libapt-pkg6.0:libapt-pkg6.0:2.4.11:*:*:*:*:*:*:*', 'cpe:2.3:a:libapt-pkg6.0:libapt_pkg6.0:2.4.11:*:*:*:*:*:*:*', 'cpe:2.3:a:libapt_pkg6.0:libapt-pkg6.0:2.4.11:*:*:*:*:*:*:*', 'cpe:2.3:a:libapt_pkg6.0:libapt_pkg6.0:2.4.11:*:*:*:*:*:*:*', 'cpe:2.3:a:libapt:libapt-pkg6.0:2.4.11:*:*:*:*:*:*:*', 'cpe:2.3:a:libapt:libapt_pkg6.0:2.4.11:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +grep,3.7-1build1,GPL-3 GPL-3+,dpkg,['cpe:2.3:a:grep:grep:3.7-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libmd0,1.0.4-1build1,BSD-2-clause BSD-2-clause-NetBSD BSD-3-clause BSD-3-clause-Aaron-D-Gifford Beerware ISC public-domain-md4 public-domain-md5 public-domain-sha1,dpkg,['cpe:2.3:a:libmd0:libmd0:1.0.4-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ConfigArgParse,1.5.5,MIT,PYTHON,"['cpe:2.3:a:python-ConfigArgParse:python-ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ConfigArgParse:python_ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ConfigArgParse:python-ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ConfigArgParse:python_ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:ConfigArgParse:python-ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:ConfigArgParse:python_ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ConfigArgParse:ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ConfigArgParse:ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:ConfigArgParse:ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_ConfigArgParse:1.5.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:ConfigArgParse:1.5.5:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sphinxcontrib-devhelp,1.0.5,Unknown,PYTHON,"['cpe:2.3:a:python-sphinxcontrib-devhelp:python-sphinxcontrib-devhelp:1.0.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-devhelp:python_sphinxcontrib_devhelp:1.0.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_devhelp:python-sphinxcontrib-devhelp:1.0.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_devhelp:python_sphinxcontrib_devhelp:1.0.5:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sphinxcontrib-applehelp,1.0.7,Unknown,PYTHON,"['cpe:2.3:a:python-sphinxcontrib-applehelp:python-sphinxcontrib-applehelp:1.0.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-applehelp:python_sphinxcontrib_applehelp:1.0.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_applehelp:python-sphinxcontrib-applehelp:1.0.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_applehelp:python_sphinxcontrib_applehelp:1.0.7:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +betterproto,1.2.5,MIT,PYTHON,"['cpe:2.3:a:daniel_g__taylor_project:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylor_project:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylorproject:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylorproject:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylor_project:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylor_project:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylorproject:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylorproject:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-betterproto:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-betterproto:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_betterproto:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_betterproto:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylor_project:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylor:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylor:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylorproject:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylor_project:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylor:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylor:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylorproject:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:betterproto:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:betterproto:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-betterproto:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_betterproto:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:daniel_g__taylor:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:danielgtaylor:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:betterproto:betterproto:1.2.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:betterproto:1.2.5:*:*:*:*:*:*:*']",Daniel G. Taylor ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Jinja2,3.1.2,BSD-3-Clause,PYTHON,"['cpe:2.3:a:armin_ronacher_project:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Jinja2:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Jinja2:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Jinja2:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Jinja2:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:Jinja2:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:Jinja2:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Jinja2:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Jinja2:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:Jinja2:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Jinja2:3.1.2:*:*:*:*:*:*:*']",Armin Ronacher ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gunicorn,21.2.0,MIT,PYTHON,"['cpe:2.3:a:benoit_chesneau_project:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneau_project:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneauproject:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneauproject:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneau_project:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneau:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneau:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneauproject:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitc_project:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitc_project:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gunicorn:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gunicorn:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gunicorn:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gunicorn:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitcproject:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitcproject:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoit_chesneau:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitc_project:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gunicorn:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gunicorn:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gunicorn:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gunicorn:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitc:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitc:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitcproject:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gunicorn:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benoitc:gunicorn:21.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:gunicorn:21.2.0:*:*:*:*:*:*:*']",Benoit Chesneau ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +bokeh,2.4.3,BSD-3-Clause,PYTHON,"['cpe:2.3:a:bokeh_team_project:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_team_project:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_teamproject:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_teamproject:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:info_project:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:info_project:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-bokeh:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-bokeh:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_bokeh:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_bokeh:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_team_project:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:infoproject:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:infoproject:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_team:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_team:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_teamproject:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:info_project:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-bokeh:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_bokeh:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:info:python-bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:info:python_bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:infoproject:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh_team:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:bokeh:bokeh:2.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:info:bokeh:2.4.3:*:*:*:*:*:*:*']",Bokeh Team ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +hpack,4.0.0,MIT License,PYTHON,"['cpe:2.3:a:cory_benfield_project:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield_project:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield_project:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-hpack:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-hpack:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_hpack:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_hpack:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hpack:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hpack:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-hpack:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_hpack:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:python-hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:python_hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hpack:hpack:4.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:hpack:4.0.0:*:*:*:*:*:*:*']",Cory Benfield ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +PyYAML,6.0.1,MIT,PYTHON,"['cpe:2.3:a:kirill_simonov_project:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov_project:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonovproject:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonovproject:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov_project:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonovproject:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyYAML:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyYAML:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyYAML:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyYAML:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi_project:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi_project:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xiproject:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xiproject:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PyYAML:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PyYAML:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyYAML:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyYAML:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi_project:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xiproject:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PyYAML:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi:PyYAML:6.0.1:*:*:*:*:*:*:*']",Kirill Simonov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +hyperframe,6.0.1,MIT License,PYTHON,"['cpe:2.3:a:cory_benfield_project:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield_project:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-hyperframe:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-hyperframe:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_hyperframe:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_hyperframe:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield_project:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:hyperframe:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:hyperframe:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-hyperframe:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_hyperframe:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:python-hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:python_hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:hyperframe:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:hyperframe:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:hyperframe:6.0.1:*:*:*:*:*:*:*']",Cory Benfield ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +unicodedata2,15.1.0,Apache License 2.0,PYTHON,"['cpe:2.3:a:mike_kaplinskiy_project:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiy_project:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiyproject:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiyproject:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-unicodedata2:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-unicodedata2:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_unicodedata2:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_unicodedata2:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiy_project:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-kaplinskiy:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-kaplinskiy:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiy:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiy:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiyproject:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-unicodedata2:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_unicodedata2:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unicodedata2:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unicodedata2:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-kaplinskiy:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_kaplinskiy:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unicodedata2:unicodedata2:15.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:unicodedata2:15.1.0:*:*:*:*:*:*:*']",Mike Kaplinskiy ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cytoolz,0.12.2,BSD,PYTHON,"['cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_md_project:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_md_project:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_mdproject:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_mdproject:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_md_project:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_md:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_md:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_mdproject:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/cytoolz\\/master\\/authors_md:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welch_project:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welch_project:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welchproject:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welchproject:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cytoolz:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cytoolz:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cytoolz:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cytoolz:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welch_project:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik-n-welch:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik-n-welch:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welch:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welch:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welchproject:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:cytoolz:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:cytoolz:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cytoolz:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cytoolz:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik-n-welch:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:erik_n_welch:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:cytoolz:cytoolz:0.12.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cytoolz:0.12.2:*:*:*:*:*:*:*']",https://raw.github.com/pytoolz/cytoolz/master/AUTHORS.md ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +diffutils,1:3.8-0ubuntu2,GFDL GPL,dpkg,['cpe:2.3:a:diffutils:diffutils:1\\:3.8-0ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +exceptiongroup,1.2.0,Unknown,PYTHON,"['cpe:2.3:a:python-exceptiongroup:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-exceptiongroup:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_exceptiongroup:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_exceptiongroup:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:exceptiongroup:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:exceptiongroup:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-exceptiongroup:exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_exceptiongroup:exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:exceptiongroup:exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_exceptiongroup:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:exceptiongroup:1.2.0:*:*:*:*:*:*:*']", >,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +fonttools,4.46.0,MIT,PYTHON,"['cpe:2.3:a:just_van_rossum_project:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossum_project:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossumproject:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossumproject:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossum_project:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fonttools:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fonttools:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fonttools:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fonttools:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossum:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossum:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossumproject:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_project:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_project:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:justproject:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:justproject:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fonttools:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fonttools:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fonttools:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fonttools:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_van_rossum:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just_project:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just:python-fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just:python_fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:justproject:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fonttools:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:fonttools:4.46.0:*:*:*:*:*:*:*', 'cpe:2.3:a:just:fonttools:4.46.0:*:*:*:*:*:*:*']",Just van Rossum ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dpkg-dev,1.21.1ubuntu2.2,BSD-2-clause GPL-2 GPL-2+ public-domain-md5 public-domain-s-s-d,dpkg,"['cpe:2.3:a:dpkg-dev:dpkg-dev:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dpkg-dev:dpkg_dev:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dpkg_dev:dpkg-dev:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dpkg_dev:dpkg_dev:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dpkg:dpkg-dev:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dpkg:dpkg_dev:1.21.1ubuntu2.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +fontconfig-config,2.13.1-4.2ubuntu5,Unknown,dpkg,"['cpe:2.3:a:fontconfig-config:fontconfig-config:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*', 'cpe:2.3:a:fontconfig-config:fontconfig_config:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*', 'cpe:2.3:a:fontconfig_config:fontconfig-config:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*', 'cpe:2.3:a:fontconfig_config:fontconfig_config:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*', 'cpe:2.3:a:fontconfig:fontconfig-config:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*', 'cpe:2.3:a:fontconfig:fontconfig_config:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +g++-11,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:g\\+\\+-11:g\\+\\+-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:g\\+\\+-11:g\\+\\+_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:g\\+\\+_11:g\\+\\+-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:g\\+\\+_11:g\\+\\+_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:g\\+\\+:g\\+\\+-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:g\\+\\+:g\\+\\+_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gcc-11,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:gcc-11:gcc-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc-11:gcc_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_11:gcc-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc_11:gcc_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc:gcc-11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:gcc:gcc_11:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +certifi,2023.11.17,MPL-2.0,PYTHON,"['cpe:2.3:a:kenneth_reitz_project:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python-certifi:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python-certifi:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python_certifi:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python_certifi:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:certifi:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:certifi:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python-certifi:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python_certifi:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python-certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python_certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:certifi:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:python:certifi:2023.11.17:*:*:*:*:*:*:*', 'cpe:2.3:a:me:certifi:2023.11.17:*:*:*:*:*:*:*']",Kenneth Reitz ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cffi,1.16.0,MIT,PYTHON,"['cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski_project:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski_project:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowskiproject:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowskiproject:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski_project:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowskiproject:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_rigo\\,_maciej_fijalkowski:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi_project:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi_project:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffiproject:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffiproject:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi_project:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cffi:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cffi:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffiproject:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cffi:python-cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cffi:python_cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cffi:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cffi:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cffi:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cffi:cffi:1.16.0:*:*:*:*:*:*:*']","Armin Rigo, Maciej Fijalkowski ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ncurses-bin,6.3-2ubuntu0.1,BSD-3-clause MIT/X11 X11,dpkg,"['cpe:2.3:a:ncurses-bin:ncurses-bin:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses-bin:ncurses_bin:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses_bin:ncurses-bin:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses_bin:ncurses_bin:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses:ncurses-bin:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses:ncurses_bin:6.3-2ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +base-files,12ubuntu4.4,GPL,dpkg,"['cpe:2.3:a:base-files:base-files:12ubuntu4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:base-files:base_files:12ubuntu4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:base_files:base-files:12ubuntu4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:base_files:base_files:12ubuntu4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:base:base-files:12ubuntu4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:base:base_files:12ubuntu4.4:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgomp1,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libgomp1:libgomp1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +perl-base,5.34.0-3ubuntu1.3,"Artistic Artistic-2 Artistic-dist BSD-3-clause BSD-3-clause-GENERIC BSD-3-clause-with-weird-numbering BSD-4-clause-POWERDOG BZIP DONT-CHANGE-THE-GPL Expat GPL-1 GPL-1+ GPL-2 GPL-2+ GPL-3+-WITH-BISON-EXCEPTION HSIEH-BSD HSIEH-DERIVATIVE LGPL-2.1 REGCOMP REGCOMP, RRA-KEEP-THIS-NOTICE SDBM-PUBLIC-DOMAIN TEXT-TABS Unicode ZLIB",dpkg,"['cpe:2.3:a:perl-base:perl-base:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl-base:perl_base:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl_base:perl-base:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl_base:perl_base:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl:perl-base:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl:perl_base:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +bsdutils,1:2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,['cpe:2.3:a:bsdutils:bsdutils:1\\:2.37.2-4ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +util-linux,2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,"['cpe:2.3:a:util-linux:util-linux:2.37.2-4ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:util-linux:util_linux:2.37.2-4ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:util_linux:util-linux:2.37.2-4ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:util_linux:util_linux:2.37.2-4ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:util:util-linux:2.37.2-4ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:util:util_linux:2.37.2-4ubuntu3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libext2fs2,1.46.5-2ubuntu1.1,GPL-2 LGPL-2,dpkg,['cpe:2.3:a:libext2fs2:libext2fs2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +nb-conda-kernels,2.3.1,Unknown,PYTHON,"['cpe:2.3:a:continuum_analytics_project:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics_project:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analyticsproject:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analyticsproject:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda-kernels:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda-kernels:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda_kernels:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda_kernels:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics_project:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics_project:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analyticsproject:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analyticsproject:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda-kernels:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda-kernels:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda_kernels:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda_kernels:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda-kernels:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda-kernels:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda_kernels:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda_kernels:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:continuum_analytics:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda-kernels:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda-kernels:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda_kernels:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda_kernels:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb-conda:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb_conda:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb:python-nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb:python_nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nb:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nb:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb-conda:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb_conda:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb:nb-conda-kernels:2.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nb:nb_conda_kernels:2.3.1:*:*:*:*:*:*:*']",Continuum Analytics,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libfontconfig1,2.13.1-4.2ubuntu5,Unknown,dpkg,['cpe:2.3:a:libfontconfig1:libfontconfig1:2.13.1-4.2ubuntu5:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +js,1.0.0,ISC,NPM,['cpe:2.3:a:js:js:1.0.0:*:*:*:*:*:*:*'],Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libfreetype6,2.11.1+dfsg-1ubuntu0.2,BSD-3-Clause BSL-1.0 FSFAP FTL GPL-2 GPL-2+ GPL-3 GPL-3+ MIT OpenGroup-BSD-like Public-Domain Zlib,dpkg,['cpe:2.3:a:libfreetype6:libfreetype6:2.11.1\\+dfsg-1ubuntu0.2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Babel,2.13.1,BSD-3-Clause,PYTHON,"['cpe:2.3:a:armin_ronacher_project:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Babel:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Babel:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Babel:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Babel:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:Babel:python-Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:Babel:python_Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Babel:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Babel:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Babel:2.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:Babel:Babel:2.13.1:*:*:*:*:*:*:*']",Armin Ronacher ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgcc-11-dev,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:libgcc-11-dev:libgcc-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc-11-dev:libgcc_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc_11_dev:libgcc-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc_11_dev:libgcc_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc-11:libgcc-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc-11:libgcc_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc_11:libgcc-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc_11:libgcc_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc:libgcc-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc:libgcc_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +npy-append-array,0.9.16,MIT,PYTHON,"['cpe:2.3:a:michael_siebert2k_project:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k_project:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2kproject:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2kproject:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert_project:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert_project:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append-array:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append-array:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append_array:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append_array:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebertproject:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebertproject:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k_project:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k_project:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael-siebert2k:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael-siebert2k:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2kproject:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2kproject:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert_project:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert_project:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append-array:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append-array:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append_array:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append_array:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append-array:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append-array:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append_array:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append_array:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebertproject:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebertproject:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael-siebert2k:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael-siebert2k:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert2k:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy-append:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy_append:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append-array:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append-array:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append_array:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append_array:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_siebert:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy-append:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy:python-npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy:python_npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy_append:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python-npy:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python_npy:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:python:npy_append_array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy:npy-append-array:0.9.16:*:*:*:*:*:*:*', 'cpe:2.3:a:npy:npy_append_array:0.9.16:*:*:*:*:*:*:*']",Michael Siebert ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgcc-s1,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:libgcc-s1:libgcc-s1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc-s1:libgcc_s1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc_s1:libgcc-s1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc_s1:libgcc_s1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc:libgcc-s1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libgcc:libgcc_s1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Brotli,1.0.9,MIT,PYTHON,"['cpe:2.3:a:brotli_authors_project:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors_project:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authorsproject:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authorsproject:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors_project:Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authorsproject:Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Brotli:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Brotli:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Brotli:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Brotli:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors:Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:Brotli:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:Brotli:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Brotli:Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Brotli:Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:Brotli:Brotli:1.0.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Brotli:1.0.9:*:*:*:*:*:*:*']",The Brotli Authors,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgcrypt20,1.9.4-3ubuntu3,GPL-2 LGPL,dpkg,['cpe:2.3:a:libgcrypt20:libgcrypt20:1.9.4-3ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +numba,0.58.1,BSD,PYTHON,"['cpe:2.3:a:python-numba:python-numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numba:python_numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numba:python-numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numba:python_numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:numba:python-numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:numba:python_numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numba:numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numba:numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:numba:0.58.1:*:*:*:*:*:*:*', 'cpe:2.3:a:numba:numba:0.58.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Brotli,1.1.0,MIT,PYTHON,"['cpe:2.3:a:brotli_authors_project:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors_project:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authorsproject:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authorsproject:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors_project:Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authorsproject:Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Brotli:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Brotli:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Brotli:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Brotli:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:brotli_authors:Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Brotli:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Brotli:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Brotli:Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Brotli:Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Brotli:Brotli:1.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Brotli:1.1.0:*:*:*:*:*:*:*']",The Brotli Authors,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgdbm-compat4,1.23-1,GFDL-NIV-1.3+ GPL-2 GPL-2+ GPL-3 GPL-3+,dpkg,"['cpe:2.3:a:libgdbm-compat4:libgdbm-compat4:1.23-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libgdbm-compat4:libgdbm_compat4:1.23-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libgdbm_compat4:libgdbm-compat4:1.23-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libgdbm_compat4:libgdbm_compat4:1.23-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libgdbm:libgdbm-compat4:1.23-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libgdbm:libgdbm_compat4:1.23-1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgdbm6,1.23-1,GFDL-NIV-1.3+ GPL-2 GPL-2+ GPL-3 GPL-3+,dpkg,['cpe:2.3:a:libgdbm6:libgdbm6:1.23-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libbsd0,0.11.5-1,BSD-2-clause BSD-2-clause-NetBSD BSD-2-clause-author BSD-2-clause-verbatim BSD-3-clause BSD-3-clause-John-Birrell BSD-3-clause-Regents BSD-3-clause-author BSD-4-clause-Christopher-G-Demetriou BSD-4-clause-Niels-Provos BSD-5-clause-Peter-Wemm Beerware Expat ISC ISC-Original public-domain,dpkg,['cpe:2.3:a:libbsd0:libbsd0:0.11.5-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libglib2.0-0,2.72.4-0ubuntu2.2,Expat GPL-2+ LGPL,dpkg,"['cpe:2.3:a:libglib2.0-0:libglib2.0-0:2.72.4-0ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libglib2.0-0:libglib2.0_0:2.72.4-0ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libglib2.0_0:libglib2.0-0:2.72.4-0ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libglib2.0_0:libglib2.0_0:2.72.4-0ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libglib2.0:libglib2.0-0:2.72.4-0ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libglib2.0:libglib2.0_0:2.72.4-0ubuntu2.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libbz2-1.0,1.0.8-5build1,BSD-variant GPL-2,dpkg,"['cpe:2.3:a:libbz2-1.0:libbz2-1.0:1.0.8-5build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libbz2-1.0:libbz2_1.0:1.0.8-5build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libbz2_1.0:libbz2-1.0:1.0.8-5build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libbz2_1.0:libbz2_1.0:1.0.8-5build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libbz2:libbz2-1.0:1.0.8-5build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libbz2:libbz2_1.0:1.0.8-5build1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dataclasses,0.8,UNKNOWN,PYTHON,"['cpe:2.3:a:python-dataclasses:python-dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dataclasses:python_dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dataclasses:python-dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dataclasses:python_dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:dataclasses:python-dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:dataclasses:python_dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dataclasses:dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dataclasses:dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:dataclasses:dataclasses:0.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dataclasses:0.8:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +referencing,0.31.1,MIT,PYTHON,"['cpe:2.3:a:julian\\+referencing_project:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencing_project:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencingproject:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencingproject:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencing_project:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencing:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencing:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencingproject:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-referencing:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-referencing:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_referencing:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_referencing:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+referencing:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-referencing:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_referencing:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:referencing:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:referencing:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:referencing:referencing:0.31.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:referencing:0.31.1:*:*:*:*:*:*:*']",Julian Berman ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +datacompy,0.8.4,Apache Software License,PYTHON,"['cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosani_project:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosani_project:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosaniproject:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosaniproject:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosani_project:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosani:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosani:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosaniproject:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ian_robertson\\,_dan_coates\\,_faisal_dosani:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosani_project:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosani_project:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosaniproject:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosaniproject:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-datacompy:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-datacompy:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_datacompy:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_datacompy:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosani_project:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal-dosani:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal-dosani:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosani:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosani:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosaniproject:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:datacompy:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:datacompy:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-datacompy:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_datacompy:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal-dosani:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:faisal_dosani:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:datacompy:datacompy:0.8.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:datacompy:0.8.4:*:*:*:*:*:*:*']","Ian Robertson, Dan Coates, Faisal Dosani ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +imagesize,1.4.1,MIT,PYTHON,"['cpe:2.3:a:yoshiki_shibukawa_project:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawa_project:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawaproject:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawaproject:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawa_project:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawa:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawa:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawaproject:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-imagesize:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-imagesize:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_imagesize:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_imagesize:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_project:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_project:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshikiproject:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshikiproject:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_shibukawa:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:imagesize:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:imagesize:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-imagesize:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_imagesize:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki_project:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshikiproject:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:imagesize:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:yoshiki:imagesize:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:imagesize:1.4.1:*:*:*:*:*:*:*']",Yoshiki Shibukawa ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dill,0.3.7,BSD-3-Clause,PYTHON,"['cpe:2.3:a:mike_mckerns_project:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckerns_project:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckernsproject:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckernsproject:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckerns_project:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckerns_project:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckernsproject:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckernsproject:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckerns_project:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckerns:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckerns:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckernsproject:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dill:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dill:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dill:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dill:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckerns_project:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckerns:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckerns:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckernsproject:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mckerns:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:dill:python-dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:dill:python_dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dill:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dill:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:mmckerns:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dill:0.3.7:*:*:*:*:*:*:*', 'cpe:2.3:a:dill:dill:0.3.7:*:*:*:*:*:*:*']",Mike McKerns ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +distributed,2023.3.2.1,BSD,PYTHON,"['cpe:2.3:a:python-distributed:python-distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-distributed:python_distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_distributed:python-distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_distributed:python_distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distributed:python-distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distributed:python_distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-distributed:distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_distributed:distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distributed:distributed:2023.3.2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:distributed:2023.3.2.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +importlib-metadata,7.0.0,Unknown,PYTHON,"['cpe:2.3:a:python-importlib-metadata:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-metadata:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_metadata:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_metadata:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-metadata:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-metadata:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_metadata:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_metadata:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-metadata:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-metadata:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_metadata:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_metadata:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-metadata:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-metadata:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_metadata:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_metadata:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:importlib_metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:importlib-metadata:7.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:importlib_metadata:7.0.0:*:*:*:*:*:*:*']",Jason R. Coombs ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +docker,5.0.3,Apache License 2.0,PYTHON,"['cpe:2.3:a:python-docker:python-docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker:python_docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:python-docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:python_docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:python-docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:python_docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker:docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:docker:5.0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:docker:5.0.3:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +docker-pycreds,0.4.0,Apache License 2.0,PYTHON,"['cpe:2.3:a:python-docker-pycreds:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker-pycreds:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker_pycreds:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker_pycreds:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown_project:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown_project:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker-pycreds:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker-pycreds:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker_pycreds:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker_pycreds:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker-pycreds:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker-pycreds:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker_pycreds:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker_pycreds:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknownproject:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknownproject:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown_project:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown_project:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker-pycreds:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker-pycreds:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker_pycreds:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker_pycreds:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknownproject:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknownproject:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docker:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docker:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:unknown:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:docker:docker_pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:docker-pycreds:0.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:docker_pycreds:0.4.0:*:*:*:*:*:*:*']",UNKNOWN ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +importlib-resources,6.1.1,Unknown,PYTHON,"['cpe:2.3:a:python-importlib-resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:importlib_resources:6.1.1:*:*:*:*:*:*:*']",Barry Warsaw ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +docutils,0.20.1,"public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)",PYTHON,"['cpe:2.3:a:david_goodger_project:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodger_project:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodgerproject:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodgerproject:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodger_project:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodger_project:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docutils:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docutils:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docutils:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docutils:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodger_project:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodgerproject:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodgerproject:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodger:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodger:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodgerproject:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:docutils:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:docutils:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodger_project:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-docutils:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_docutils:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodger:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodger:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodgerproject:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:david_goodger:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:docutils:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:goodger:docutils:0.20.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:docutils:0.20.1:*:*:*:*:*:*:*']",David Goodger ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +traitlets,5.14.0,"BSD 3-Clause License + + - Copyright (c) 2001-, IPython Development Team + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:ipython_development_team_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +triton,2.0.0,Unknown,PYTHON,"['cpe:2.3:a:philippe_tillet_project:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tillet_project:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tilletproject:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tilletproject:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tillet_project:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tillet:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tillet:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tilletproject:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-triton:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-triton:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_triton:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_triton:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:phil_project:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:phil_project:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philproject:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philproject:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philippe_tillet:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-triton:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_triton:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:triton:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:triton:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:phil_project:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:phil:python-triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:phil:python_triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:philproject:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:triton:triton:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:phil:triton:2.0.0:*:*:*:*:*:*:*']",Philippe Tillet ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tritonclient,2.26.0,BSD,PYTHON,"['cpe:2.3:a:sw_dl_triton_project:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_triton_project:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc__project:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc__project:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tritonclient:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tritonclient:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tritonclient:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tritonclient:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_tritonproject:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_tritonproject:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc_project:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc_project:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_triton_project:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc__project:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tritonclient:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tritonclient:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw-dl-triton:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw-dl-triton:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_triton:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_triton:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_tritonproject:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tritonclient:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tritonclient:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc_:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc_:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc_project:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw-dl-triton:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sw_dl_triton:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tritonclient:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_inc_:tritonclient:2.26.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tritonclient:2.26.0:*:*:*:*:*:*:*']",NVIDIA Inc. ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libkeyutils1,1.6.1-2ubuntu3,GPL-2 GPL-2+ LGPL-2 LGPL-2+,dpkg,['cpe:2.3:a:libkeyutils1:libkeyutils1:1.6.1-2ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +PyJWT,2.8.0,MIT,PYTHON,"['cpe:2.3:a:jose_padilla_project:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padilla_project:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padillaproject:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padillaproject:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hello_project:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hello_project:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padilla_project:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:helloproject:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:helloproject:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padilla:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padilla:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padillaproject:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyJWT:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyJWT:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyJWT:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyJWT:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hello_project:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:PyJWT:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:PyJWT:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hello:python-PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hello:python_PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:helloproject:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jose_padilla:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyJWT:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyJWT:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:PyJWT:PyJWT:2.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:hello:PyJWT:2.8.0:*:*:*:*:*:*:*']",Jose Padilla ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +liblcms2-2,2.12~rc1-2build2,GPL-2 GPL-2+ GPL-3 MIT,dpkg,"['cpe:2.3:a:liblcms2-2:liblcms2-2:2.12\\~rc1-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblcms2-2:liblcms2_2:2.12\\~rc1-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblcms2_2:liblcms2-2:2.12\\~rc1-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblcms2_2:liblcms2_2:2.12\\~rc1-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblcms2:liblcms2-2:2.12\\~rc1-2build2:*:*:*:*:*:*:*', 'cpe:2.3:a:liblcms2:liblcms2_2:2.12\\~rc1-2build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libacl1,2.3.1-1,GPL-2 GPL-2+ LGPL-2+ LGPL-2.1,dpkg,['cpe:2.3:a:libacl1:libacl1:2.3.1-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +liblsan0,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:liblsan0:liblsan0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libasan6,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libasan6:libasan6:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +liblzma5,5.2.5-2ubuntu1,Autoconf GPL-2 GPL-2+ GPL-3 LGPL-2 LGPL-2.1 LGPL-2.1+ PD PD-debian config-h noderivs permissive-fsf permissive-nowarranty probably-PD,dpkg,['cpe:2.3:a:liblzma5:liblzma5:5.2.5-2ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libmpc3,1.2.1-2build1,LGPL-3,dpkg,['cpe:2.3:a:libmpc3:libmpc3:1.2.1-2build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Jinja2,3.1.2,BSD-3-Clause,PYTHON,"['cpe:2.3:a:armin_ronacher_project:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Jinja2:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Jinja2:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Jinja2:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Jinja2:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:Jinja2:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:Jinja2:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Jinja2:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Jinja2:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:Jinja2:Jinja2:3.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Jinja2:3.1.2:*:*:*:*:*:*:*']",Armin Ronacher ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Mako,1.3.0,MIT,PYTHON,"['cpe:2.3:a:mike_bayer_project:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer_project:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_project:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_project:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer_project:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mikeproject:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mikeproject:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Mako:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Mako:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Mako:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Mako:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_project:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Mako:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Mako:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike:python-Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike:python_Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mikeproject:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Mako:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Mako:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Mako:Mako:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike:Mako:1.3.0:*:*:*:*:*:*:*']",Mike Bayer ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sphinxcontrib-htmlhelp,2.0.4,Unknown,PYTHON,"['cpe:2.3:a:python-sphinxcontrib-htmlhelp:python-sphinxcontrib-htmlhelp:2.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sphinxcontrib-htmlhelp:python_sphinxcontrib_htmlhelp:2.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_htmlhelp:python-sphinxcontrib-htmlhelp:2.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sphinxcontrib_htmlhelp:python_sphinxcontrib_htmlhelp:2.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +blinker,1.7.0,Unknown,PYTHON,"['cpe:2.3:a:jason_kirtland_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cubinlinker,0.3.0,Unknown,PYTHON,"['cpe:2.3:a:python-cubinlinker:python-cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cubinlinker:python_cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cubinlinker:python-cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cubinlinker:python_cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cubinlinker:python-cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cubinlinker:python_cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cubinlinker:cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cubinlinker:cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cubinlinker:cubinlinker:0.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cubinlinker:0.3.0:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +boltons,23.0.0,BSD,PYTHON,"['cpe:2.3:a:mahmoud_hashemi_project:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemi_project:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemiproject:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemiproject:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemi_project:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemi:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemi:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemiproject:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_project:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_project:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoudproject:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoudproject:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-boltons:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-boltons:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_boltons:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_boltons:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_hashemi:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud_project:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:boltons:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:boltons:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoudproject:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-boltons:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_boltons:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:boltons:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mahmoud:boltons:23.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:boltons:23.0.0:*:*:*:*:*:*:*']",Mahmoud Hashemi ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +typing_extensions,4.8.0,Unknown,PYTHON,"['cpe:2.3:a:python-typing-extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:typing_extensions:4.8.0:*:*:*:*:*:*:*']"," <""Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee"" >",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +idna,3.4,Unknown,PYTHON,"['cpe:2.3:a:kim_davies_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +idna,3.6,Unknown,PYTHON,"['cpe:2.3:a:kim_davies_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +kiwisolver,1.4.5,"========================= + The Kiwi licensing terms + ========================= + Kiwi is licensed under the terms of the Modified BSD License (also known as + New or Revised BSD), as follows: + + Copyright (c) 2013, Nucleic Development Team + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of the Nucleic Development Team nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + About Kiwi + ---------- + Chris Colbert began the Kiwi project in December 2013 in an effort to + create a blisteringly fast UI constraint solver. Chris is still the + project lead. + + The Nucleic Development Team is the set of all contributors to the Nucleic + project and its subprojects. + + The core team that coordinates development on GitHub can be found here: + http://github.com/nucleic. The current team consists of: + + * Chris Colbert + + Our Copyright Policy + -------------------- + Nucleic uses a shared copyright model. Each contributor maintains copyright + over their contributions to Nucleic. But, it is important to note that these + contributions are typically only changes to the repositories. Thus, the Nucleic + source code, in its entirety is not the copyright of any single person or + institution. Instead, it is the collective copyright of the entire Nucleic + Development Team. If individual contributors want to maintain a record of what + changes/contributions they have specific copyright on, they should indicate + their copyright in the commit message of the change, when they commit the + change to one of the Nucleic repositories. + + With this in mind, the following banner should be used in any source code file + to indicate the copyright and license terms: + + #------------------------------------------------------------------------------ + # Copyright (c) 2013, Nucleic Development Team. + # + # Distributed under the terms of the Modified BSD License. + # + # The full license is in the file LICENSE, distributed with this software. + #------------------------------------------------------------------------------ + ",PYTHON,"['cpe:2.3:a:nucleic_development_team_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libarchive-c,5.0,CC0,PYTHON,"['cpe:2.3:a:python-libarchive-c:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive-c:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive_c:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive_c:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco_project:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco_project:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changacoproject:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changacoproject:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive-c:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive-c:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive_c:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive_c:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive-c:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive-c:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive_c:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive_c:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libarchive:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libarchive:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco_project:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco_project:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changacoproject:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changacoproject:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive-c:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive-c:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive_c:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive_c:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libarchive:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:changaco:libarchive_c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:libarchive-c:5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:libarchive_c:5.0:*:*:*:*:*:*:*']",Changaco ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libmambapy,1.5.0,Unknown,PYTHON,"['cpe:2.3:a:quantstack_project:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstack_project:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libmambapy:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libmambapy:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libmambapy:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libmambapy:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstackproject:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstackproject:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:info_project:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:info_project:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:infoproject:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:infoproject:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstack_project:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libmambapy:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libmambapy:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-libmambapy:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_libmambapy:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstack:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstack:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstackproject:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:info_project:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:info:python-libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:info:python_libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:infoproject:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:libmambapy:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:quantstack:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:libmambapy:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:info:libmambapy:1.5.0:*:*:*:*:*:*:*']",QuantStack ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +llvmlite,0.41.1,BSD,PYTHON,"['cpe:2.3:a:python-llvmlite:python-llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-llvmlite:python_llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_llvmlite:python-llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_llvmlite:python_llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:llvmlite:python-llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:llvmlite:python_llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-llvmlite:llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_llvmlite:llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:llvmlite:llvmlite:0.41.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:llvmlite:0.41.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pip,23.3.1,MIT,PYTHON,"['cpe:2.3:a:pip_developers_project:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developers_project:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developersproject:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developersproject:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developers_project:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developers:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developers:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developersproject:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pip:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pip:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pip:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pip:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip_developers:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pypa:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pypa:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip:python-pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip:python_pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pip:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pip:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pypa:pip:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pip:pip:23.3.1:*:*:*:*:*:*:*']",The pip developers ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgraphite2-3,1.3.14-1build2,Artistic GPL-1 GPL-1+ GPL-2 GPL-2+ LGPL-2.1 LGPL-2.1+ MPL-1.1 custom-sil-open-font-license public-domain,dpkg,"['cpe:2.3:a:libgraphite2-3:libgraphite2-3:1.3.14-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libgraphite2-3:libgraphite2_3:1.3.14-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libgraphite2_3:libgraphite2-3:1.3.14-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libgraphite2_3:libgraphite2_3:1.3.14-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libgraphite2:libgraphite2-3:1.3.14-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:libgraphite2:libgraphite2_3:1.3.14-1build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgssapi-krb5-2,1.19.2-2ubuntu0.3,GPL-2,dpkg,"['cpe:2.3:a:libgssapi-krb5-2:libgssapi-krb5-2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi-krb5-2:libgssapi_krb5_2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi_krb5_2:libgssapi-krb5-2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi_krb5_2:libgssapi_krb5_2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi-krb5:libgssapi-krb5-2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi-krb5:libgssapi_krb5_2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi_krb5:libgssapi-krb5-2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi_krb5:libgssapi_krb5_2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi:libgssapi-krb5-2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgssapi:libgssapi_krb5_2:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +morpheus,23.11.1,Apache,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-morpheus:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-morpheus:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_morpheus:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_morpheus:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:morpheus:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:morpheus:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-morpheus:morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_morpheus:morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:morpheus:morpheus:23.11.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:morpheus:23.11.1:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tomli,2.0.1,Unknown,PYTHON,"['cpe:2.3:a:taneli_hukkinen_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mpmath,1.3.0,BSD,PYTHON,"['cpe:2.3:a:fredrik_johansson_project:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johansson_project:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johanssonproject:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johanssonproject:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johansson_project:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik-johansson:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik-johansson:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johansson:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johansson:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johanssonproject:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mpmath:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mpmath:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mpmath:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mpmath:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik-johansson:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:fredrik_johansson:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mpmath:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mpmath:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mpmath:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mpmath:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mpmath:mpmath:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:mpmath:1.3.0:*:*:*:*:*:*:*']",Fredrik Johansson ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pytz,2023.3.post1,MIT,PYTHON,"['cpe:2.3:a:stuart_bishop_project:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop_project:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishopproject:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishopproject:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop_project:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_project:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_project:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishopproject:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuartproject:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuartproject:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pytz:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pytz:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pytz:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pytz:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_project:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart_bishop:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuartproject:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pytz:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pytz:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytz:python-pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytz:python_pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:stuart:pytz:2023.3.post1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytz:pytz:2023.3.post1:*:*:*:*:*:*:*']",Stuart Bishop ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libidn2-0,2.3.2-2build1,GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL-3 LGPL-3+ Unicode,dpkg,"['cpe:2.3:a:libidn2-0:libidn2-0:2.3.2-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libidn2-0:libidn2_0:2.3.2-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libidn2_0:libidn2-0:2.3.2-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libidn2_0:libidn2_0:2.3.2-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libidn2:libidn2-0:2.3.2-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libidn2:libidn2_0:2.3.2-2build1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pyzmq,25.1.2,LGPL+BSD,PYTHON,"['cpe:2.3:a:brian_e__granger\\,_min_ragan_kelley_project:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelley_project:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelleyproject:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelleyproject:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelley_project:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelley:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelley:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelleyproject:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_e__granger\\,_min_ragan_kelley:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_dev_project:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_dev_project:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_devproject:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_devproject:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyzmq:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyzmq:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyzmq:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyzmq:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_dev_project:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq-dev:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq-dev:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_dev:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_dev:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_devproject:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyzmq:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyzmq:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:pyzmq:python-pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:pyzmq:python_pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq-dev:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:zeromq_dev:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pyzmq:25.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:pyzmq:pyzmq:25.1.2:*:*:*:*:*:*:*']","Brian E. Granger, Min Ragan-Kelley ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cudf,23.6.1,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:python-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:python_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cudf:cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cudf:cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:cudf:cudf:23.6.1:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libitm1,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libitm1:libitm1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +rich,13.7.0,MIT,PYTHON,"['cpe:2.3:a:will_mcgugan_project:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcgugan_project:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcguganproject:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcguganproject:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcgugan_project:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcgugan_project:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcguganproject:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcguganproject:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcgugan_project:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcgugan:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcgugan:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcguganproject:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcgugan_project:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rich:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rich:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rich:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rich:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcgugan:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcgugan:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcguganproject:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:will_mcgugan:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rich:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rich:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rich:python-rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rich:python_rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:willmcgugan:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:rich:13.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rich:rich:13.7.0:*:*:*:*:*:*:*']",Will McGugan ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libjpeg-turbo8,2.1.2-0ubuntu1,LGPL-2.1,dpkg,"['cpe:2.3:a:libjpeg-turbo8:libjpeg-turbo8:2.1.2-0ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libjpeg-turbo8:libjpeg_turbo8:2.1.2-0ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libjpeg_turbo8:libjpeg-turbo8:2.1.2-0ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libjpeg_turbo8:libjpeg_turbo8:2.1.2-0ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libjpeg:libjpeg-turbo8:2.1.2-0ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libjpeg:libjpeg_turbo8:2.1.2-0ubuntu1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cycler,0.12.1,"Copyright (c) 2015, matplotlib project + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the matplotlib project nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:thomas_a_caswell_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sysvinit-utils,3.01-1ubuntu1,GPL-2 GPL-2+,dpkg,"['cpe:2.3:a:sysvinit-utils:sysvinit-utils:3.01-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:sysvinit-utils:sysvinit_utils:3.01-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:sysvinit_utils:sysvinit-utils:3.01-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:sysvinit_utils:sysvinit_utils:3.01-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:sysvinit:sysvinit-utils:3.01-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:sysvinit:sysvinit_utils:3.01-1ubuntu1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libasound2-data,1.2.6.1-1ubuntu1,LGPL-2.1 LPGL-2.1+,dpkg,"['cpe:2.3:a:libasound2-data:libasound2-data:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libasound2-data:libasound2_data:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libasound2_data:libasound2-data:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libasound2_data:libasound2_data:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libasound2:libasound2-data:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*', 'cpe:2.3:a:libasound2:libasound2_data:1.2.6.1-1ubuntu1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tar,1.34+dfsg-1ubuntu0.1.22.04.1,GPL-2 GPL-3,dpkg,['cpe:2.3:a:tar:tar:1.34\\+dfsg-1ubuntu0.1.22.04.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +charset-normalizer,3.2.0,MIT,PYTHON,"['cpe:2.3:a:python-charset-normalizer:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset-normalizer:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset-normalizer:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset-normalizer:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:charset_normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:charset-normalizer:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:charset_normalizer:3.2.0:*:*:*:*:*:*:*']",Ahmed TAHRI ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cryptography,41.0.3,Apache-2.0 OR BSD-3-Clause,PYTHON,"['cpe:2.3:a:python_cryptographic_authority_and_individual_contributors_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +charset-normalizer,3.3.2,MIT,PYTHON,"['cpe:2.3:a:python-charset-normalizer:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset-normalizer:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset-normalizer:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset-normalizer:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset_normalizer:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri_project:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahriproject:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset-normalizer:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset_normalizer:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-charset:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_charset:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed-tahri:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ahmed_tahri:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:charset:charset_normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:charset-normalizer:3.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:charset_normalizer:3.3.2:*:*:*:*:*:*:*']",Ahmed TAHRI ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libattr1,1:2.5.1-1build1,GPL-2 GPL-2+ LGPL-2+ LGPL-2.1,dpkg,['cpe:2.3:a:libattr1:libattr1:1\\:2.5.1-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libseccomp2,2.5.3-2ubuntu2,LGPL-2.1,dpkg,['cpe:2.3:a:libseccomp2:libseccomp2:2.5.3-2ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libselinux1,3.3-1build2,GPL-2 LGPL-2.1,dpkg,['cpe:2.3:a:libselinux1:libselinux1:3.3-1build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +colorama,0.4.6,Unknown,PYTHON,"['cpe:2.3:a:jonathan_hartley_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libbinutils,2.38-4ubuntu2.3,GFDL GPL LGPL,dpkg,['cpe:2.3:a:libbinutils:libbinutils:2.38-4ubuntu2.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libblkid1,2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,['cpe:2.3:a:libblkid1:libblkid1:2.37.2-4ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsmartcols1,2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,['cpe:2.3:a:libsmartcols1:libsmartcols1:2.37.2-4ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libss2,1.46.5-2ubuntu1.1,Unknown,dpkg,['cpe:2.3:a:libss2:libss2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +bzip2,1.0.8-5build1,BSD-variant GPL-2,dpkg,['cpe:2.3:a:bzip2:bzip2:1.0.8-5build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnuma1,2.0.14-3ubuntu2,GPL LGPL,dpkg,['cpe:2.3:a:libnuma1:libnuma1:2.0.14-3ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-toolkit-11-8-config-common,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-toolkit-11-8-config-common:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-8-config-common:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_8_config_common:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_8_config_common:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-8-config:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-8-config:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_8_config:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_8_config:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-8:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-8:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_8:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_8:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-toolkit-11-8-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_toolkit_11_8_config_common:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +entrypoints,0.4,Unknown,PYTHON,"['cpe:2.3:a:thomas_kluyver_project:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyver_project:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyverproject:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyverproject:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-entrypoints:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-entrypoints:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_entrypoints:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_entrypoints:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyver_project:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyver:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyver:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyverproject:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_project:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_project:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomasproject:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomasproject:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:entrypoints:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:entrypoints:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-entrypoints:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_entrypoints:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kluyver:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_project:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas:python-entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas:python_entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomasproject:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:entrypoints:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:entrypoints:0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas:entrypoints:0.4:*:*:*:*:*:*:*']",Thomas Kluyver ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libc6,2.35-0ubuntu3.5,GFDL-1.3 GPL-2 LGPL-2.1,dpkg,['cpe:2.3:a:libc6:libc6:2.35-0ubuntu3.5:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +findutils,4.8.0-1ubuntu3,GFDL-1.3 GPL-3,dpkg,['cpe:2.3:a:findutils:findutils:4.8.0-1ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +g++,4:11.2.0-1ubuntu1,GPL-2,dpkg,['cpe:2.3:a:g\\+\\+:g\\+\\+:4\\:11.2.0-1ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcublas-11-8,11.11.3.6-1,Unknown,dpkg,"['cpe:2.3:a:libcublas-11-8:libcublas-11-8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas-11-8:libcublas_11_8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas_11_8:libcublas-11-8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas_11_8:libcublas_11_8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas-11:libcublas-11-8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas-11:libcublas_11_8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas_11:libcublas-11-8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas_11:libcublas_11_8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas:libcublas-11-8:11.11.3.6-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcublas:libcublas_11_8:11.11.3.6-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcom-err2,1.46.5-2ubuntu1.1,Unknown,dpkg,"['cpe:2.3:a:libcom-err2:libcom-err2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcom-err2:libcom_err2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcom_err2:libcom-err2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcom_err2:libcom_err2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcom:libcom-err2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcom:libcom_err2:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ncurses-base,6.3-2ubuntu0.1,BSD-3-clause MIT/X11 X11,dpkg,"['cpe:2.3:a:ncurses-base:ncurses-base:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses-base:ncurses_base:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses_base:ncurses-base:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses_base:ncurses_base:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses:ncurses-base:6.3-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ncurses:ncurses_base:6.3-2ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcups2,2.4.1op1-1ubuntu4.7,Apache-2.0 Apache-2.0-with-GPL2-LGPL2-Exception BSD-2-Clause FSFUL Zlib,dpkg,['cpe:2.3:a:libcups2:libcups2:2.4.1op1-1ubuntu4.7:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +apt,2.4.11,GPL-2 GPLv2+,dpkg,['cpe:2.3:a:apt:apt:2.4.11:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcrypt-dev,1:4.4.27-1,Unknown,dpkg,"['cpe:2.3:a:libcrypt-dev:libcrypt-dev:1\\:4.4.27-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcrypt-dev:libcrypt_dev:1\\:4.4.27-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcrypt_dev:libcrypt-dev:1\\:4.4.27-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcrypt_dev:libcrypt_dev:1\\:4.4.27-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcrypt:libcrypt-dev:1\\:4.4.27-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcrypt:libcrypt_dev:1\\:4.4.27-1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +base-passwd,3.5.52build1,GPL-2 public-domain,dpkg,"['cpe:2.3:a:base-passwd:base-passwd:3.5.52build1:*:*:*:*:*:*:*', 'cpe:2.3:a:base-passwd:base_passwd:3.5.52build1:*:*:*:*:*:*:*', 'cpe:2.3:a:base_passwd:base-passwd:3.5.52build1:*:*:*:*:*:*:*', 'cpe:2.3:a:base_passwd:base_passwd:3.5.52build1:*:*:*:*:*:*:*', 'cpe:2.3:a:base:base-passwd:3.5.52build1:*:*:*:*:*:*:*', 'cpe:2.3:a:base:base_passwd:3.5.52build1:*:*:*:*:*:*:*']",Colin Watson (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcurand-11-8,10.3.0.86-1,Unknown,dpkg,"['cpe:2.3:a:libcurand-11-8:libcurand-11-8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand-11-8:libcurand_11_8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand_11_8:libcurand-11-8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand_11_8:libcurand_11_8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand-11:libcurand-11-8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand-11:libcurand_11_8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand_11:libcurand-11-8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand_11:libcurand_11_8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand:libcurand-11-8:10.3.0.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcurand:libcurand_11_8:10.3.0.86-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +openssl,3.0.2-0ubuntu1.12,Apache-2.0 Artistic GPL-1 GPL-1+,dpkg,['cpe:2.3:a:openssl:openssl:3.0.2-0ubuntu1.12:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libdbus-1-3,1.12.20-2ubuntu4.1,AFL-2.1 BSD-3-clause BSD-3-clause-generic Expat GPL-2 GPL-2+ Tcl-BSDish g10-permissive,dpkg,"['cpe:2.3:a:libdbus-1-3:libdbus-1-3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus-1-3:libdbus_1_3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus_1_3:libdbus-1-3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus_1_3:libdbus_1_3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus-1:libdbus-1-3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus-1:libdbus_1_3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus_1:libdbus-1-3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus_1:libdbus_1_3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus:libdbus-1-3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libdbus:libdbus_1_3:1.12.20-2ubuntu4.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +patch,2.7.6-7build2,GPL,dpkg,['cpe:2.3:a:patch:patch:2.7.6-7build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-cudart-dev-11-8,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-cudart-dev-11-8:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-dev-11-8:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_dev_11_8:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_dev_11_8:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-dev-11:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-dev-11:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_dev_11:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_dev_11:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-dev:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart-dev:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_dev:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart_dev:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cudart:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cudart:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-cudart-dev-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_cudart_dev_11_8:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libmpfr6,4.1.0-3build3,LGPL-3,dpkg,['cpe:2.3:a:libmpfr6:libmpfr6:4.1.0-3build3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-compat-11-8,520.61.05-1,Unknown,dpkg,"['cpe:2.3:a:cuda-compat-11-8:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compat-11-8:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compat_11_8:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compat_11_8:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compat-11:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compat-11:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compat_11:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compat_11:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compat:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compat:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compat:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compat:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-compat-11-8:520.61.05-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_compat_11_8:520.61.05-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnsl2,1.3.0-2build2,BSD-3-clause GPL-2 GPL-2+-autoconf-exception GPL-2+-libtool-exception GPL-3 GPL-3+-autoconf-exception LGPL-2.1 LGPL-2.1+ MIT permissive-autoconf-m4 permissive-autoconf-m4-no-warranty permissive-configure permissive-fsf permissive-makefile-in,dpkg,['cpe:2.3:a:libnsl2:libnsl2:1.3.0-2build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +fastrlock,0.8.2,MIT style,PYTHON,"['cpe:2.3:a:stefan_behnel_project:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnel_project:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnelproject:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnelproject:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_ml_project:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_ml_project:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fastrlock:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fastrlock:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fastrlock:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fastrlock:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_mlproject:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_mlproject:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnel_project:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnel:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnel:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnelproject:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_ml_project:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:fastrlock:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:fastrlock:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fastrlock:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fastrlock:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan-ml:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan-ml:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_ml:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_ml:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_mlproject:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_behnel:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:fastrlock:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan-ml:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_ml:fastrlock:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:fastrlock:0.8.2:*:*:*:*:*:*:*']",Stefan Behnel ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcap2,1:2.44-1ubuntu0.22.04.1,BSD-3-clause GPL-2 GPL-2+,dpkg,['cpe:2.3:a:libcap2:libcap2:1\\:2.44-1ubuntu0.22.04.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gnupg-l10n,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,"['cpe:2.3:a:gnupg-l10n:gnupg-l10n:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg-l10n:gnupg_l10n:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg_l10n:gnupg-l10n:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg_l10n:gnupg_l10n:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg:gnupg-l10n:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg:gnupg_l10n:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gnupg-utils,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,"['cpe:2.3:a:gnupg-utils:gnupg-utils:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg-utils:gnupg_utils:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg_utils:gnupg-utils:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg_utils:gnupg_utils:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg:gnupg-utils:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gnupg:gnupg_utils:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpg-agent,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,"['cpe:2.3:a:gpg-agent:gpg-agent:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg-agent:gpg_agent:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_agent:gpg-agent:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg_agent:gpg_agent:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg:gpg-agent:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*', 'cpe:2.3:a:gpg:gpg_agent:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libc-dev-bin,2.35-0ubuntu3.5,GFDL-1.3 GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libc-dev-bin:libc-dev-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc-dev-bin:libc_dev_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc_dev_bin:libc-dev-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc_dev_bin:libc_dev_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc-dev:libc-dev-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc-dev:libc_dev_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc_dev:libc-dev-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc_dev:libc_dev_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc:libc-dev-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc:libc_dev_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcusolver-11-8,11.4.1.48-1,Unknown,dpkg,"['cpe:2.3:a:libcusolver-11-8:libcusolver-11-8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver-11-8:libcusolver_11_8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver_11_8:libcusolver-11-8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver_11_8:libcusolver_11_8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver-11:libcusolver-11-8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver-11:libcusolver_11_8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver_11:libcusolver-11-8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver_11:libcusolver_11_8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver:libcusolver-11-8:11.4.1.48-1:*:*:*:*:*:*:*', 'cpe:2.3:a:libcusolver:libcusolver_11_8:11.4.1.48-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcbor0.8,0.8.0-2ubuntu1,Apache-2.0 Expat,dpkg,['cpe:2.3:a:libcbor0.8:libcbor0.8:0.8.0-2ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +prometheus-flask-exporter,0.23.0,MIT,PYTHON,"['cpe:2.3:a:python-prometheus-flask-exporter:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask-exporter:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask_exporter:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask_exporter:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask-exporter:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask-exporter:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask_exporter:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask_exporter:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask-exporter:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask-exporter:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask_exporter:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask_exporter:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam_project:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam_project:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask-exporter:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask-exporter:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask_exporter:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask_exporter:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adamproject:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adamproject:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus-flask:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus_flask:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86_project:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86_project:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86project:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86project:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam_project:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam_project:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adamproject:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adamproject:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prometheus:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prometheus:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus-flask:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus_flask:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86_project:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86_project:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86project:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86project:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:viktor_adam:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:prometheus:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rycus86:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:prometheus-flask-exporter:0.23.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:prometheus_flask_exporter:0.23.0:*:*:*:*:*:*:*']",Viktor Adam ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libdpkg-perl,1.21.1ubuntu2.2,BSD-2-clause GPL-2 GPL-2+ public-domain-md5 public-domain-s-s-d,dpkg,"['cpe:2.3:a:libdpkg-perl:libdpkg-perl:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libdpkg-perl:libdpkg_perl:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libdpkg_perl:libdpkg-perl:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libdpkg_perl:libdpkg_perl:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libdpkg:libdpkg-perl:1.21.1ubuntu2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libdpkg:libdpkg_perl:1.21.1ubuntu2.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +binutils-common,2.38-4ubuntu2.3,GFDL GPL LGPL,dpkg,"['cpe:2.3:a:binutils-common:binutils-common:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-common:binutils_common:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_common:binutils-common:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_common:binutils_common:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils:binutils-common:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils:binutils_common:2.38-4ubuntu2.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +conda,23.3.1,BSD-3-Clause,PYTHON,"['cpe:2.3:a:anaconda\\,_inc__project:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc__project:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc__project:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:python-conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:python_conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:conda:23.3.1:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:conda:23.3.1:*:*:*:*:*:*:*']","Anaconda, Inc. ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +binutils-x86-64-linux-gnu,2.38-4ubuntu2.3,GFDL GPL LGPL,dpkg,"['cpe:2.3:a:binutils-x86-64-linux-gnu:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86-64-linux-gnu:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86_64_linux_gnu:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86_64_linux_gnu:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86-64-linux:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86-64-linux:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86_64_linux:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86_64_linux:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86-64:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86-64:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86_64:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86_64:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils-x86:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils_x86:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils:binutils-x86-64-linux-gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:binutils:binutils_x86_64_linux_gnu:2.38-4ubuntu2.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-cuobjdump-11-8,11.8.86-1,Unknown,dpkg,"['cpe:2.3:a:cuda-cuobjdump-11-8:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuobjdump-11-8:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuobjdump_11_8:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuobjdump_11_8:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuobjdump-11:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuobjdump-11:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuobjdump_11:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuobjdump_11:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuobjdump:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuobjdump:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuobjdump:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuobjdump:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-cuobjdump-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_cuobjdump_11_8:11.8.86-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-cupti-11-8,11.8.87-1,Unknown,dpkg,"['cpe:2.3:a:cuda-cupti-11-8:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cupti-11-8:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cupti_11_8:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cupti_11_8:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cupti-11:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cupti-11:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cupti_11:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cupti_11:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cupti:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cupti:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cupti:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cupti:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-cupti-11-8:11.8.87-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_cupti_11_8:11.8.87-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-cuxxfilt-11-8,11.8.86-1,Unknown,dpkg,"['cpe:2.3:a:cuda-cuxxfilt-11-8:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuxxfilt-11-8:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuxxfilt_11_8:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuxxfilt_11_8:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuxxfilt-11:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuxxfilt-11:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuxxfilt_11:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuxxfilt_11:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuxxfilt:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cuxxfilt:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuxxfilt:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cuxxfilt:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-cuxxfilt-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_cuxxfilt_11_8:11.8.86-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +zlib1g,1:1.2.11.dfsg-2ubuntu9.2,Zlib,dpkg,['cpe:2.3:a:zlib1g:zlib1g:1\\:1.2.11.dfsg-2ubuntu9.2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-gdb-11-8,11.8.86-1,Unknown,dpkg,"['cpe:2.3:a:cuda-gdb-11-8:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-gdb-11-8:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_gdb_11_8:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_gdb_11_8:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-gdb-11:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-gdb-11:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_gdb_11:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_gdb_11:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-gdb:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-gdb:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_gdb:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_gdb:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-gdb-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_gdb_11_8:11.8.86-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-keyring,1.1-1,Unknown,dpkg,"['cpe:2.3:a:cuda-keyring:cuda-keyring:1.1-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-keyring:cuda_keyring:1.1-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_keyring:cuda-keyring:1.1-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_keyring:cuda_keyring:1.1-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-keyring:1.1-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_keyring:1.1-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-nvcc-11-8,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-nvcc-11-8:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvcc-11-8:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvcc_11_8:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvcc_11_8:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvcc-11:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvcc-11:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvcc_11:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvcc_11:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvcc:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvcc:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvcc:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvcc:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-nvcc-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_nvcc_11_8:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +psutil,5.9.5,BSD-3-Clause,PYTHON,"['cpe:2.3:a:giampaolo_rodola_project:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola_project:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodolaproject:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodolaproject:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola_project:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola_project:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola_project:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodolaproject:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodolaproject:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodolaproject:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-psutil:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-psutil:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_psutil:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_psutil:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola_project:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g-rodola:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g-rodola:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodolaproject:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:psutil:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:psutil:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-psutil:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_psutil:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g-rodola:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:psutil:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:psutil:5.9.5:*:*:*:*:*:*:*']",Giampaolo Rodola ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ptxcompiler,0.8.1,Apache 2.0,PYTHON,"['cpe:2.3:a:python-ptxcompiler:python-ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ptxcompiler:python_ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ptxcompiler:python-ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ptxcompiler:python_ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ptxcompiler:python-ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ptxcompiler:python_ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ptxcompiler:ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ptxcompiler:ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:ptxcompiler:ptxcompiler:0.8.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:ptxcompiler:0.8.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnettle8,3.7.3-1build2,Expat GAP GPL GPL-2 GPL-2+ GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-3+ public-domain,dpkg,['cpe:2.3:a:libnettle8:libnettle8:3.7.3-1build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libp11-kit0,0.24.0-6build1,Apache-2.0 BSD-3-Clause ISC ISC+IBM LGPL-2.1 LGPL-2.1+ permissive-like-automake-output same-as-rest-of-p11kit,dpkg,"['cpe:2.3:a:libp11-kit0:libp11-kit0:0.24.0-6build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libp11-kit0:libp11_kit0:0.24.0-6build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libp11_kit0:libp11-kit0:0.24.0-6build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libp11_kit0:libp11_kit0:0.24.0-6build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libp11:libp11-kit0:0.24.0-6build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libp11:libp11_kit0:0.24.0-6build1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-nvprune-11-8,11.8.86-1,Unknown,dpkg,"['cpe:2.3:a:cuda-nvprune-11-8:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvprune-11-8:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvprune_11_8:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvprune_11_8:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvprune-11:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvprune-11:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvprune_11:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvprune_11:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvprune:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvprune:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvprune:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvprune:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-nvprune-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_nvprune_11_8:11.8.86-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libk5crypto3,1.19.2-2ubuntu0.3,GPL-2,dpkg,['cpe:2.3:a:libk5crypto3:libk5crypto3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libkrb5-3,1.19.2-2ubuntu0.3,GPL-2,dpkg,"['cpe:2.3:a:libkrb5-3:libkrb5-3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libkrb5-3:libkrb5_3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libkrb5_3:libkrb5-3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libkrb5_3:libkrb5_3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libkrb5:libkrb5-3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libkrb5:libkrb5_3:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libksba8,1.6.0-2ubuntu0.2,FSFUL GPL-3 LGPL-2.1-or-later,dpkg,['cpe:2.3:a:libksba8:libksba8:1.6.0-2ubuntu0.2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jq,1.6-2.1ubuntu3,CC-BY-3.0 Expat GPL-2 GPL-2.0+ MIT,dpkg,['cpe:2.3:a:jq:jq:1.6-2.1ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libldap-2.5-0,2.5.16+dfsg-0ubuntu0.22.04.1,Unknown,dpkg,"['cpe:2.3:a:libldap-2.5-0:libldap-2.5-0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap-2.5-0:libldap_2.5_0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap_2.5_0:libldap-2.5-0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap_2.5_0:libldap_2.5_0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap-2.5:libldap-2.5-0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap-2.5:libldap_2.5_0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap_2.5:libldap-2.5-0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap_2.5:libldap_2.5_0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap:libldap-2.5-0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libldap:libldap_2.5_0:2.5.16\\+dfsg-0ubuntu0.22.04.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpgsm,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:gpgsm:gpgsm:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +java-common,0.72build2,GPL-2 GPL-2+,dpkg,"['cpe:2.3:a:java-common:java-common:0.72build2:*:*:*:*:*:*:*', 'cpe:2.3:a:java-common:java_common:0.72build2:*:*:*:*:*:*:*', 'cpe:2.3:a:java_common:java-common:0.72build2:*:*:*:*:*:*:*', 'cpe:2.3:a:java_common:java_common:0.72build2:*:*:*:*:*:*:*', 'cpe:2.3:a:java:java-common:0.72build2:*:*:*:*:*:*:*', 'cpe:2.3:a:java:java_common:0.72build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Flask,3.0.0,Unknown,PYTHON,"['cpe:2.3:a:python-Flask:python-Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Flask:python_Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Flask:python-Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Flask:python_Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Flask:python-Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Flask:python_Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Flask:Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Flask:Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Flask:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Flask:Flask:3.0.0:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +coreutils,8.32-4.1ubuntu1,GPL-3,dpkg,['cpe:2.3:a:coreutils:coreutils:8.32-4.1ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cryptography,41.0.7,Apache-2.0 OR BSD-3-Clause,PYTHON,"['cpe:2.3:a:python_cryptographic_authority_and_individual_contributors_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +h2,4.1.0,MIT License,PYTHON,"['cpe:2.3:a:cory_benfield_project:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield_project:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield_project:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfieldproject:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-h2:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-h2:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_h2:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_h2:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_benfield:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory_project:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:coryproject:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:h2:python-h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:h2:python_h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-h2:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_h2:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cory:h2:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:h2:h2:4.1.0:*:*:*:*:*:*:*']",Cory Benfield ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cachetools,5.3.2,MIT,PYTHON,"['cpe:2.3:a:thomas_kemmer_project:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmer_project:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmerproject:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmerproject:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cachetools:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cachetools:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cachetools:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cachetools:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmer_project:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmer_project:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmer_project:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmerproject:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmerproject:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmer:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmer:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmerproject:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:cachetools:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:cachetools:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cachetools:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cachetools:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmer_project:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmer:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmer:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmerproject:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_kemmer:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:cachetools:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:tkemmer:cachetools:5.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cachetools:5.3.2:*:*:*:*:*:*:*']",Thomas Kemmer ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Pygments,2.17.2,BSD-2-Clause,PYTHON,"['cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +PyYAML,6.0.1,MIT,PYTHON,"['cpe:2.3:a:kirill_simonov_project:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov_project:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonovproject:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonovproject:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov_project:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonovproject:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyYAML:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyYAML:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyYAML:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyYAML:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi_project:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi_project:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xiproject:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xiproject:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:kirill_simonov:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PyYAML:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PyYAML:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PyYAML:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PyYAML:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi_project:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi:python-PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi:python_PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xiproject:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PyYAML:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:PyYAML:6.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:xi:PyYAML:6.0.1:*:*:*:*:*:*:*']",Kirill Simonov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Pygments,2.17.2,BSD-2-Clause,PYTHON,"['cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +url-normalize,1.4.3,MIT,PYTHON,"['cpe:2.3:a:nikolay_panov_project:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov_project:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panovproject:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panovproject:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url-normalize:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url-normalize:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url_normalize:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url_normalize:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github_project:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github_project:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov_project:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov_project:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:githubproject:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:githubproject:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panovproject:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panovproject:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url-normalize:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url-normalize:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url_normalize:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url_normalize:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url-normalize:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url-normalize:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url_normalize:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url_normalize:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github_project:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github_project:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:githubproject:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:githubproject:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:nikolay_panov:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url-normalize:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url-normalize:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url_normalize:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url_normalize:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-url:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_url:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url:python-url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url:python_url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:github:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:url_normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url:url-normalize:1.4.3:*:*:*:*:*:*:*', 'cpe:2.3:a:url:url_normalize:1.4.3:*:*:*:*:*:*:*']",Nikolay Panov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dask,2023.3.2,BSD,PYTHON,"['cpe:2.3:a:python-dask:python-dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:python_dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:python-dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:python_dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:python-dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:python_dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dask:2023.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:dask:2023.3.2:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +merlin-core,23.6.0,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin-core:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin-core:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin_core:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin_core:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin-core:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin-core:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin_core:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin_core:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin-core:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin-core:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin_core:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin_core:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-merlin:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_merlin:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin-core:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin-core:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin_core:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin_core:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:merlin:merlin_core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:merlin-core:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:merlin_core:23.6.0:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ca-certificates-java,20190909ubuntu1.2,GPL,dpkg,"['cpe:2.3:a:ca-certificates-java:ca-certificates-java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca-certificates-java:ca_certificates_java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca_certificates_java:ca-certificates-java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca_certificates_java:ca_certificates_java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca-certificates:ca-certificates-java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca-certificates:ca_certificates_java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca_certificates:ca-certificates-java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca_certificates:ca_certificates_java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca:ca-certificates-java:20190909ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:ca:ca_certificates_java:20190909ubuntu1.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +greenlet,3.0.1,MIT License,PYTHON,"['cpe:2.3:a:alexey_borzenkov_project:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkov_project:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkovproject:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkovproject:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkov_project:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkov:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkov:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkovproject:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-greenlet:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-greenlet:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_greenlet:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_greenlet:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snaury_project:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snaury_project:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snauryproject:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snauryproject:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:alexey_borzenkov:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:greenlet:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:greenlet:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-greenlet:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_greenlet:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snaury_project:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snaury:python-greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snaury:python_greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snauryproject:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:greenlet:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:greenlet:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:snaury:greenlet:3.0.1:*:*:*:*:*:*:*']",Alexey Borzenkov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-cccl-11-8,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-cccl-11-8:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cccl-11-8:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cccl_11_8:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cccl_11_8:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cccl-11:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cccl-11:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cccl_11:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cccl_11:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cccl:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-cccl:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cccl:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_cccl:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-cccl-11-8:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_cccl_11_8:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ordered-set,4.1.0,Unknown,PYTHON,"['cpe:2.3:a:elia_robyn_lake_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-toolkit-11-config-common,11.8.89-1,Unknown,dpkg,"['cpe:2.3:a:cuda-toolkit-11-config-common:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-config-common:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_config_common:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_config_common:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-config:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11-config:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_config:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11_config:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit-11:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit_11:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-toolkit:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_toolkit:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-toolkit-11-config-common:11.8.89-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_toolkit_11_config_common:11.8.89-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-compiler-11-8,11.8.0-1,Unknown,dpkg,"['cpe:2.3:a:cuda-compiler-11-8:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compiler-11-8:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compiler_11_8:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compiler_11_8:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compiler-11:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compiler-11:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compiler_11:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compiler_11:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compiler:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-compiler:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compiler:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_compiler:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-compiler-11-8:11.8.0-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_compiler_11_8:11.8.0-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jupyter_core,5.5.0,"BSD 3-Clause License + + - Copyright (c) 2015-, Jupyter Development Team + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:jupyter_development_team_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +adduser,3.118ubuntu5,GPL-2,dpkg,['cpe:2.3:a:adduser:adduser:3.118ubuntu5:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +packaging,23.2,Unknown,PYTHON,"['cpe:2.3:a:donald_stufft_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +openjdk-11-jre-headless,11.0.21+9-0ubuntu1~22.04,Apache-2.0 GPL GPL-2 LGPL LGPL-2 LGPL-2-1 MIT,dpkg,"['cpe:2.3:a:openjdk-11-jre-headless:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk-11-jre-headless:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk_11_jre_headless:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk_11_jre_headless:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk-11-jre:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk-11-jre:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk_11_jre:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk_11_jre:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk-11:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk-11:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk_11:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk_11:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk:openjdk-11-jre-headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:openjdk:openjdk_11_jre_headless:11.0.21\\+9-0ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +databricks-cli,0.18.0,Apache License 2.0,PYTHON,"['cpe:2.3:a:python-databricks-cli:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks-cli:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks_cli:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks_cli:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen_project:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen_project:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chenproject:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chenproject:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen_project:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen_project:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchenproject:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchenproject:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks-cli:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks-cli:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks_cli:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks_cli:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks-cli:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks-cli:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks_cli:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks_cli:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen_project:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen_project:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chenproject:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chenproject:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen_project:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen_project:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchenproject:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchenproject:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-databricks:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_databricks:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks-cli:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks-cli:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks_cli:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks_cli:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_chen:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:andrewchen:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:databricks_cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:databricks-cli:0.18.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:databricks_cli:0.18.0:*:*:*:*:*:*:*']",Andrew Chen ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +bc,1.07.1-3build1,GPL-2 GPL-2.0+ X11 permissive permissive',dpkg,['cpe:2.3:a:bc:bc:1.07.1-3build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pandas,1.3.5,BSD-3-Clause,PYTHON,"['cpe:2.3:a:pandas_development_team_project:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_team_project:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_teamproject:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_teamproject:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_team_project:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_team:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_team:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_teamproject:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_dev_project:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_dev_project:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_devproject:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_devproject:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_development_team:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pandas:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pandas:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pandas:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pandas:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_dev_project:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas-dev:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas-dev:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_dev:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_dev:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_devproject:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pandas:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pandas:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas-dev:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas_dev:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:pandas:pandas:1.3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pandas:1.3.5:*:*:*:*:*:*:*']",The Pandas Development Team ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +partd,1.4.1,BSD,PYTHON,"['cpe:2.3:a:python-partd:python-partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-partd:python_partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_partd:python-partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_partd:python_partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:partd:python-partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:partd:python_partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-partd:partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_partd:partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:partd:1.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:partd:partd:1.4.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgpg-error0,1.43-3,BSD-3-clause GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ g10-permissive,dpkg,"['cpe:2.3:a:libgpg-error0:libgpg-error0:1.43-3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgpg-error0:libgpg_error0:1.43-3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgpg_error0:libgpg-error0:1.43-3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgpg_error0:libgpg_error0:1.43-3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgpg:libgpg-error0:1.43-3:*:*:*:*:*:*:*', 'cpe:2.3:a:libgpg:libgpg_error0:1.43-3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-nvdisasm-11-8,11.8.86-1,Unknown,dpkg,"['cpe:2.3:a:cuda-nvdisasm-11-8:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvdisasm-11-8:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvdisasm_11_8:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvdisasm_11_8:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvdisasm-11:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvdisasm-11:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvdisasm_11:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvdisasm_11:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvdisasm:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda-nvdisasm:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvdisasm:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda_nvdisasm:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda-nvdisasm-11-8:11.8.86-1:*:*:*:*:*:*:*', 'cpe:2.3:a:cuda:cuda_nvdisasm_11_8:11.8.86-1:*:*:*:*:*:*:*']",cudatools (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cuda-python,11.8.3,"NVIDIA SOFTWARE LICENSE + + This license is a legal agreement between you and NVIDIA Corporation (""NVIDIA"") and governs your use of the NVIDIA CUDA Python software and materials provided hereunder (""SOFTWARE""). + + This license can be accepted only by an adult of legal age of majority in the country in which the SOFTWARE is used. If you are under the legal age of majority, you must ask your parent or legal guardian to consent to this license. By taking delivery of the SOFTWARE, you affirm that you have reached the legal age of majority, you accept the terms of this license, and you take legal and financial responsibility for the actions of your permitted users. + + You agree to use the SOFTWARE only for purposes that are permitted by (a) this license, and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions. + + 1. LICENSE. Subject to the terms of this license, NVIDIA grants you a non-exclusive limited license to: (a) install and use the SOFTWARE, and (b) distribute the SOFTWARE subject to the distribution requirements described in this license. NVIDIA reserves all rights, title and interest in and to the SOFTWARE not expressly granted to you under this license. + + 2. DISTRIBUTION REQUIREMENTS. These are the distribution requirements for you to exercise the distribution grant: + a. The terms under which you distribute the SOFTWARE must be consistent with the terms of this license, including (without limitation) terms relating to the license grant and license restrictions and protection of NVIDIA's intellectual property rights. + b. You agree to notify NVIDIA in writing of any known or suspected distribution or use of the SOFTWARE not in compliance with the requirements of this license, and to enforce the terms of your agreements with respect to distributed SOFTWARE. + + 3. LIMITATIONS. Your license to use the SOFTWARE is restricted as follows: + a. The SOFTWARE is licensed for you to develop applications only for use in systems with NVIDIA GPUs. + b. You may not reverse engineer, decompile or disassemble, or remove copyright or other proprietary notices from any portion of the SOFTWARE or copies of the SOFTWARE. + c. You may not modify or create derivative works of any portion of the SOFTWARE. + d. You may not bypass, disable, or circumvent any technical measure, encryption, security, digital rights management or authentication mechanism in the SOFTWARE. + e. You may not use the SOFTWARE in any manner that would cause it to become subject to an open source software license. As examples, licenses that require as a condition of use, modification, and/or distribution that the SOFTWARE be (i) disclosed or distributed in source code form; (ii) licensed for the purpose of making derivative works; or (iii) redistributable at no charge. + f. Unless you have an agreement with NVIDIA for this purpose, you may not use the SOFTWARE with any system or application where the use or failure of the system or application can reasonably be expected to threaten or result in personal injury, death, or catastrophic loss. Examples include use in avionics, navigation, military, medical, life support or other life critical applications. NVIDIA does not design, test or manufacture the SOFTWARE for these critical uses and NVIDIA shall not be liable to you or any third party, in whole or in part, for any claims or damages arising from such uses. + g. You agree to defend, indemnify and hold harmless NVIDIA and its affiliates, and their respective employees, contractors, agents, officers and directors, from and against any and all claims, damages, obligations, losses, liabilities, costs or debt, fines, restitutions and expenses (including but not limited to attorney's fees and costs incident to establishing the right of indemnification) arising out of or related to use of the SOFTWARE outside of the scope of this Agreement, or not in compliance with its terms. + + 4. PRE-RELEASE. SOFTWARE versions identified as alpha, beta, preview, early access or otherwise as pre-release may not be fully functional, may contain errors or design flaws, and may have reduced or different security, privacy, availability, and reliability standards relative to commercial versions of NVIDIA software and materials. You may use a pre-release SOFTWARE version at your own risk, understanding that these versions are not intended for use in production or business-critical systems. + + 5. OWNERSHIP. The SOFTWARE and the related intellectual property rights therein are and will remain the sole and exclusive property of NVIDIA or its licensors. The SOFTWARE is copyrighted and protected by the laws of the United States and other countries, and international treaty provisions. NVIDIA may make changes to the SOFTWARE, at any time without notice, but is not obligated to support or update the SOFTWARE. + + 6. COMPONENTS UNDER OTHER LICENSES. The SOFTWARE may include NVIDIA or third-party components with separate legal notices or terms as may be described in proprietary notices accompanying the SOFTWARE. If and to the extent there is a conflict between the terms in this license and the license terms associated with a component, the license terms associated with the components control only to the extent necessary to resolve the conflict. + + 7. FEEDBACK. You may, but don't have to, provide to NVIDIA any Feedback. ""Feedback"" means any suggestions, bug fixes, enhancements, modifications, feature requests or other feedback regarding the SOFTWARE. For any Feedback that you voluntarily provide, you hereby grant NVIDIA and its affiliates a perpetual, non-exclusive, worldwide, irrevocable license to use, reproduce, modify, license, sublicense (through multiple tiers of sublicensees), and distribute (through multiple tiers of distributors) the Feedback without the payment of any royalties or fees to you. NVIDIA will use Feedback at its choice. + + 8. NO WARRANTIES. THE SOFTWARE IS PROVIDED ""AS IS"" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. NVIDIA DOES NOT WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION THEREOF WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ALL ERRORS WILL BE CORRECTED. + + 9. LIMITATIONS OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY LAW, NVIDIA AND ITS AFFILIATES SHALL NOT BE LIABLE FOR ANY SPECIAL, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR ANY LOST PROFITS, PROJECT DELAYS, LOSS OF USE, LOSS OF DATA OR LOSS OF GOODWILL, OR THE COSTS OF PROCURING SUBSTITUTE PRODUCTS, ARISING OUT OF OR IN CONNECTION WITH THIS LICENSE OR THE USE OR PERFORMANCE OF THE SOFTWARE, WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON BREACH OF CONTRACT, BREACH OF WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR ANY OTHER CAUSE OF ACTION OR THEORY OF LIABILITY, EVEN IF NVIDIA HAS PREVIOUSLY BEEN ADVISED OF, OR COULD REASONABLY HAVE FORESEEN, THE POSSIBILITY OF SUCH DAMAGES. IN NO EVENT WILL NVIDIA'S AND ITS AFFILIATES TOTAL CUMULATIVE LIABILITY UNDER OR ARISING OUT OF THIS LICENSE EXCEED US$10.00. THE NATURE OF THE LIABILITY OR THE NUMBER OF CLAIMS OR SUITS SHALL NOT ENLARGE OR EXTEND THIS LIMIT. + + 10. TERMINATION. Your rights under this license will terminate automatically without notice from NVIDIA if you fail to comply with any term and condition of this license or if you commence or participate in any legal proceeding against NVIDIA with respect to the SOFTWARE. NVIDIA may terminate this license with advance written notice to you if NVIDIA decides to no longer provide the SOFTWARE in a country or, in NVIDIA's sole discretion, the continued use of it is no longer commercially viable. Upon any termination of this license, you agree to promptly discontinue use of the SOFTWARE and destroy all copies in your possession or control. Your prior distributions in accordance with this license are not affected by the termination of this license. All provisions of this license will survive termination, except for the license granted to you. + + 11. APPLICABLE LAW. This license will be governed in all respects by the laws of the United States and of the State of Delaware as those laws are applied to contracts entered into and performed entirely within Delaware by Delaware residents, without regard to the conflicts of laws principles. The United Nations Convention on Contracts for the International Sale of Goods is specifically disclaimed. You agree to all terms of this Agreement in the English language. The state or federal courts residing in Santa Clara County, California shall have exclusive jurisdiction over any dispute or claim arising out of this license. Notwithstanding this, you agree that NVIDIA shall still be allowed to apply for injunctive remedies or an equivalent type of urgent legal relief in any jurisdiction. + + 12. NO ASSIGNMENT. This license and your rights and obligations thereunder may not be assigned by you by any means or operation of law without NVIDIA's permission. Any attempted assignment not approved by NVIDIA in writing shall be void and of no effect. + + 13. EXPORT. The SOFTWARE is subject to United States export laws and regulations. You agree that you will not ship, transfer or export the SOFTWARE into any country, or use the SOFTWARE in any manner, prohibited by the United States Bureau of Industry and Security or economic sanctions regulations administered by the U.S. Department of Treasury's Office of Foreign Assets Control (OFAC), or any applicable export laws, restrictions or regulations. These laws include restrictions on destinations, end users and end use. By accepting this license, you confirm that you are not a resident or citizen of any country currently embargoed by the U.S. and that you are not otherwise prohibited from receiving the SOFTWARE. + + 14. GOVERNMENT USE. The SOFTWARE has been developed entirely at private expense and is ""commercial items"" consisting of ""commercial computer software"" and ""commercial computer software documentation"" provided with RESTRICTED RIGHTS. Use, duplication or disclosure by the U.S. Government or a U.S. Government subcontractor is subject to the restrictions in this license pursuant to DFARS 227.7202-3(a) or as set forth in subparagraphs (b)(1) and (2) of the Commercial Computer Software - Restricted Rights clause at FAR 52.227-19, as applicable. Contractor/manufacturer is NVIDIA, 2788 San Tomas Expressway, Santa Clara, CA 95051. + + 15. ENTIRE AGREEMENT. This license is the final, complete and exclusive agreement between the parties relating to the subject matter of this license and supersedes all prior or contemporaneous understandings and agreements relating to this subject matter, whether oral or written. If any court of competent jurisdiction determines that any provision of this license is illegal, invalid or unenforceable, the remaining provisions will remain in full force and effect. This license may only be modified in a writing signed by an authorized representative of each party. + + (v. May 12, 2021) + ",PYTHON,"['cpe:2.3:a:nvidia_corporation_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +conda-package-handling,2.2.0,Unknown,PYTHON,"['cpe:2.3:a:python-conda-package-handling:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package-handling:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package_handling:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package_handling:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc__project:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc__project:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package-handling:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package-handling:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package_handling:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package_handling:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package-handling:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package-handling:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package_handling:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package_handling:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc__project:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc__project:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package-handling:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package-handling:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package_handling:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package_handling:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_project:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda-package:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda_package:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:anaconda\\,_inc_:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda-package:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_package:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda_project:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:python-conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:python_conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:condaproject:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-conda:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_conda:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:conda_package_handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:conda-package-handling:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:conda:conda_package_handling:2.2.0:*:*:*:*:*:*:*']","Anaconda, Inc. ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpgconf,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:gpgconf:gpgconf:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +typing-utils,0.1.0,Apache License 2.0,PYTHON,"['cpe:2.3:a:python-typing-utils:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-utils:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_utils:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_utils:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang__project:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang__project:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_project:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_project:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiangproject:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiangproject:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-utils:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-utils:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_utils:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_utils:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-utils:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-utils:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_utils:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_utils:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang__project:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang__project:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang-:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang-:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_project:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_project:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiangproject:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiangproject:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python-typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python_typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-utils:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-utils:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_utils:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_utils:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang-:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang-:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang_:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:bojiang:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:typing_utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:typing-utils:0.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:typing_utils:0.1.0:*:*:*:*:*:*:*']",bojiang ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +conda_index,0.3.0,Unknown,PYTHON,"['cpe:2.3:a:\\""anaconda\\,_inc__\\&_contributors\\""_\\>",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +six,1.16.0,MIT,PYTHON,"['cpe:2.3:a:benjamin_peterson_project:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_peterson_project:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_petersonproject:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_petersonproject:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_peterson_project:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_peterson:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_peterson:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_petersonproject:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_project:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_project:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjaminproject:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjaminproject:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_peterson:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-six:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-six:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_six:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_six:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin_project:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjaminproject:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-six:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_six:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:six:python-six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:six:python_six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:benjamin:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:six:1.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:six:six:1.16.0:*:*:*:*:*:*:*']",Benjamin Peterson ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Markdown,3.5.1,"Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) + Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) + Copyright 2004 Manfred Stienstra (the original version) + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Python Markdown Project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ",PYTHON,"['cpe:2.3:a:manfred_stienstra\\,_yuri_takhteyev_project:python-Markdown:3.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:manfred_stienstra\\,_yuri_takhteyev_project:python_Markdown:3.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:manfred_stienstra\\,_yuri_takhteyevproject:python-Markdown:3.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:manfred_stienstra\\,_yuri_takhteyevproject:python_Markdown:3.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:waylan_limberg_\\>",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +MarkupSafe,2.1.3,BSD-3-Clause,PYTHON,"['cpe:2.3:a:python-MarkupSafe:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-MarkupSafe:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_MarkupSafe:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_MarkupSafe:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:MarkupSafe:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:MarkupSafe:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-MarkupSafe:MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_MarkupSafe:MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:MarkupSafe:MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:MarkupSafe:2.1.3:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +MarkupSafe,2.1.3,BSD-3-Clause,PYTHON,"['cpe:2.3:a:python-MarkupSafe:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-MarkupSafe:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_MarkupSafe:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_MarkupSafe:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:MarkupSafe:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:MarkupSafe:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-MarkupSafe:MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_MarkupSafe:MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:MarkupSafe:MarkupSafe:2.1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:MarkupSafe:2.1.3:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ucf,3.0043,GPL-2,dpkg,['cpe:2.3:a:ucf:ucf:3.0043:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Pillow,10.1.0,HPND,PYTHON,"['cpe:2.3:a:jeffrey_a__clark_\\(alex\\)_project:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\)_project:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\)project:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\)project:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\)_project:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\):python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\):python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\)project:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffrey_a__clark_\\(alex\\):Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclark_project:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclark_project:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclarkproject:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclarkproject:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Pillow:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Pillow:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Pillow:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Pillow:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclark_project:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Pillow:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Pillow:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclark:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclark:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclarkproject:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Pillow:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Pillow:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:Pillow:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:aclark:Pillow:10.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Pillow:10.1.0:*:*:*:*:*:*:*']",Jeffrey A. Clark (Alex) ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libkrb5support0,1.19.2-2ubuntu0.3,GPL-2,dpkg,['cpe:2.3:a:libkrb5support0:libkrb5support0:1.19.2-2ubuntu0.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +hostname,3.23ubuntu2,GPL-2,dpkg,['cpe:2.3:a:hostname:hostname:3.23ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +conda-build,3.28.1,"Except where noted below, conda is released under the following terms: + + (c) 2012 Continuum Analytics, Inc. / http://continuum.io + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Continuum Analytics, Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL CONTINUUM ANALYTICS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Exceptions + ========== + + versioneer.py is Public Domain",PYTHON,"['cpe:2.3:a:\\""anaconda\\,_inc_\\""_\\>",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +typing_extensions,4.8.0,Unknown,PYTHON,"['cpe:2.3:a:python-typing-extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing-extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing_extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing_extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing-extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing_extensions:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-typing:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_typing:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python-typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python-typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:python_typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:typing_extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:typing-extensions:4.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:typing:typing_extensions:4.8.0:*:*:*:*:*:*:*']"," <""Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee"" >",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ujson,5.8.0,Unknown,PYTHON,"['cpe:2.3:a:jonas_tarnstrom_project:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstrom_project:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstromproject:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstromproject:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstrom_project:ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstrom:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstrom:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstromproject:ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ujson:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ujson:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ujson:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ujson:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jonas_tarnstrom:ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ujson:ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ujson:ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ujson:python-ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ujson:python_ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:ujson:5.8.0:*:*:*:*:*:*:*', 'cpe:2.3:a:ujson:ujson:5.8.0:*:*:*:*:*:*:*']",Jonas Tarnstrom,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +conda-libmamba-solver,23.3.0,"BSD 3-Clause License + + Copyright (c) 2022, Anaconda, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + --- + + This work also includes code borrowed from mamba.utils v0.19, licensed as BSD 3-Clause",PYTHON,"['cpe:2.3:a:\\""anaconda\\,_inc_\\""_\\>",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mlflow,2.9.1,Apache License 2.0,PYTHON,"['cpe:2.3:a:databricks_project:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks_project:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricksproject:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricksproject:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mlflow:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mlflow:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mlflow:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mlflow:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks_project:mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricksproject:mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:mlflow:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:mlflow:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mlflow:mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mlflow:mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:databricks:mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:mlflow:mlflow:2.9.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:mlflow:2.9.1:*:*:*:*:*:*:*']",Databricks,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +googleapis-common-protos,1.61.0,Apache-2.0,PYTHON,"['cpe:2.3:a:python-googleapis-common-protos:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common-protos:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common_protos:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common_protos:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages_project:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages_project:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packagesproject:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packagesproject:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common-protos:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common-protos:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common_protos:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common_protos:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common-protos:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common-protos:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common_protos:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common_protos:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages_project:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages_project:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-packages:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-packages:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packagesproject:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packagesproject:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc_project:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc_project:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llcproject:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llcproject:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common-protos:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common-protos:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common_protos:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common_protos:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis-common:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis_common:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-packages:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-packages:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_packages:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc_project:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc_project:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llcproject:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llcproject:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis-common:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis_common:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-googleapis:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_googleapis:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:google_llc:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:googleapis:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:googleapis-common-protos:1.61.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:googleapis_common_protos:1.61.0:*:*:*:*:*:*:*']",Google LLC ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dask-cuda,23.6.0,Apache-2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cuda:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cuda:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cuda:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cuda:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cuda:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cuda:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cuda:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cuda:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cuda:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cuda:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cuda:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cuda:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:python-dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:python_dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cuda:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cuda:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cuda:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cuda:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dask_cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:dask-cuda:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:dask_cuda:23.6.0:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +more-itertools,10.1.0,Unknown,PYTHON,"['cpe:2.3:a:erik_rose_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dask-cudf,23.6.1,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cudf:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cudf:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cudf:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cudf:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cudf:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cudf:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cudf:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cudf:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cudf:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask-cudf:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cudf:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask_cudf:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:python-dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:python_dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dask:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dask:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cudf:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask-cudf:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cudf:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask_cudf:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:dask_cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:dask-cudf:23.6.1:*:*:*:*:*:*:*', 'cpe:2.3:a:dask:dask_cudf:23.6.1:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +grpcio,1.54.2,Apache License 2.0,PYTHON,"['cpe:2.3:a:grpc_authors_project:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authors_project:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authorsproject:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authorsproject:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_io_project:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_io_project:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_ioproject:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_ioproject:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authors_project:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-grpcio:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-grpcio:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_grpcio:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_grpcio:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authors:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authors:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authorsproject:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_io_project:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc-io:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc-io:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_io:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_io:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_ioproject:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpcio:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpcio:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-grpcio:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_grpcio:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_authors:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc-io:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpc_io:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:grpcio:grpcio:1.54.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:grpcio:1.54.2:*:*:*:*:*:*:*']",The gRPC Authors ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +packaging,23.1,Unknown,PYTHON,"['cpe:2.3:a:donald_stufft_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +grpclib,0.4.6,BSD-3-Clause,PYTHON,"['cpe:2.3:a:vladimir_magamedov_project:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedov_project:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedovproject:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedovproject:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedov_project:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedov:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedov:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedovproject:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_project:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_project:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimirproject:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimirproject:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python-grpclib:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python-grpclib:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python_grpclib:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python_grpclib:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_magamedov:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir_project:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimirproject:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:grpclib:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:grpclib:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python-grpclib:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python_grpclib:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:vladimir:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:grpclib:grpclib:0.4.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python:grpclib:0.4.6:*:*:*:*:*:*:*']",Vladimir Magamedov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +python-rapidjson,1.13,MIT License,PYTHON,"['cpe:2.3:a:ken_robbins_project:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_robbins_project:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_robbinsproject:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_robbinsproject:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rapidjson:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rapidjson:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rapidjson:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rapidjson:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_project:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_project:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_robbins:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken_robbins:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:kenproject:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:kenproject:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken:python-rapidjson:1.13:*:*:*:*:*:*:*', 'cpe:2.3:a:ken:python_rapidjson:1.13:*:*:*:*:*:*:*']",Ken Robbins ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +querystring-parser,1.2.4,UNKNOWN,PYTHON,"['cpe:2.3:a:python-querystring-parser:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring-parser:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring_parser:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring_parser:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring-parser:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring-parser:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring_parser:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring_parser:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring-parser:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring-parser:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring_parser:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring_parser:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii_project:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii_project:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni_project:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni_project:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniiproject:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniiproject:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniproject:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniproject:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-querystring:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_querystring:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring-parser:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring-parser:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring_parser:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring_parser:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii_project:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii_project:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni_project:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni_project:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniiproject:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniiproject:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni:python-querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni:python_querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniproject:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berniproject:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:querystring:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bernii:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:querystring_parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni:querystring-parser:1.2.4:*:*:*:*:*:*:*', 'cpe:2.3:a:berni:querystring_parser:1.2.4:*:*:*:*:*:*:*']",bernii ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +requests,2.31.0,Apache 2.0,PYTHON,"['cpe:2.3:a:kenneth_reitz_project:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz_project:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitzproject:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:kenneth_reitz:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me_project:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python-requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me:python_requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:meproject:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:requests:2.31.0:*:*:*:*:*:*:*', 'cpe:2.3:a:me:requests:2.31.0:*:*:*:*:*:*:*']",Kenneth Reitz ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cupy,12.2.0,MIT License,PYTHON,"['cpe:2.3:a:seiya_tokui_project:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokui_project:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokuiproject:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokuiproject:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokui_project:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokui_project:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokui_project:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokuiproject:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokuiproject:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cupy:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cupy:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cupy:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cupy:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokui:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokui:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokuiproject:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokui_project:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokui:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokui:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokuiproject:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cupy:python-cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cupy:python_cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cupy:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cupy:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:seiya_tokui:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tokui:cupy:12.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cupy:cupy:12.2.0:*:*:*:*:*:*:*']",Seiya Tokui ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +rmm,23.6.0,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rmm:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rmm:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rmm:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rmm:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-rmm:rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_rmm:rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rmm:python-rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rmm:python_rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:rmm:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:rmm:rmm:23.6.0:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +contourpy,1.2.0,"BSD 3-Clause License + + Copyright (c) 2021-2023, ContourPy Developers. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:ian_thomas_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libatomic1,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libatomic1:libatomic1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsasl2-modules-db,2.1.27+dfsg2-3ubuntu1.2,BSD-2-clause BSD-2.2-clause BSD-3-clause BSD-3-clause-JANET BSD-3-clause-PADL BSD-4-clause BSD-4-clause-UC FSFULLR GPL-3 GPL-3+ IBM-as-is MIT-CMU MIT-Export MIT-OpenVision OpenLDAP OpenSSL RSA-MD SSLeay,dpkg,"['cpe:2.3:a:libsasl2-modules-db:libsasl2-modules-db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2-modules-db:libsasl2_modules_db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2_modules_db:libsasl2-modules-db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2_modules_db:libsasl2_modules_db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2-modules:libsasl2-modules-db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2-modules:libsasl2_modules_db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2_modules:libsasl2-modules-db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2_modules:libsasl2_modules_db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2:libsasl2-modules-db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libsasl2:libsasl2_modules_db:2.1.27\\+dfsg2-3ubuntu1.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +cloudpickle,3.0.0,BSD-3-Clause,PYTHON,"['cpe:2.3:a:cloudpickle_developer_team_project:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_team_project:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_teamproject:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_teamproject:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_team_project:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_team:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_team:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_teamproject:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle_developer_team:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cloudpickle:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cloudpickle:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cloudpickle:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cloudpickle:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipe_project:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipe_project:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipeproject:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipeproject:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-cloudpickle:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_cloudpickle:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipe_project:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipe:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipe:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipeproject:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpickle:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cloudpipe:cloudpickle:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:cloudpickle:3.0.0:*:*:*:*:*:*:*']",The cloudpickle developer team ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libavahi-common-data,0.8-5ubuntu5.2,GPL GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libavahi-common-data:libavahi-common-data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi-common-data:libavahi_common_data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_common_data:libavahi-common-data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_common_data:libavahi_common_data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi-common:libavahi-common-data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi-common:libavahi_common_data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_common:libavahi-common-data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_common:libavahi_common_data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi:libavahi-common-data:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi:libavahi_common_data:0.8-5ubuntu5.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libavahi-common3,0.8-5ubuntu5.2,GPL GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libavahi-common3:libavahi-common3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi-common3:libavahi_common3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_common3:libavahi-common3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi_common3:libavahi_common3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi:libavahi-common3:0.8-5ubuntu5.2:*:*:*:*:*:*:*', 'cpe:2.3:a:libavahi:libavahi_common3:0.8-5ubuntu5.2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsepol2,3.3-1build1,GPL LGPL,dpkg,['cpe:2.3:a:libsepol2:libsepol2:3.3-1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +anyio,3.7.1,MIT,PYTHON,"['cpe:2.3:a:python-anyio:python-anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-anyio:python_anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_anyio:python-anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_anyio:python_anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anyio:python-anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anyio:python_anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-anyio:anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_anyio:anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:anyio:3.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anyio:anyio:3.7.1:*:*:*:*:*:*:*']", >,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +appdirs,1.4.4,MIT,PYTHON,"['cpe:2.3:a:trent_mick_project:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mick_project:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mickproject:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mickproject:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-appdirs:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-appdirs:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_appdirs:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_appdirs:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentm_project:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentm_project:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentmproject:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentmproject:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mick_project:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mick:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mick:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mickproject:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:appdirs:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:appdirs:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-appdirs:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_appdirs:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentm_project:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentm:python-appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentm:python_appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentmproject:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trent_mick:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:appdirs:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:appdirs:1.4.4:*:*:*:*:*:*:*', 'cpe:2.3:a:trentm:appdirs:1.4.4:*:*:*:*:*:*:*']",Trent Mick ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +asn1crypto,1.5.1,MIT,PYTHON,"['cpe:2.3:a:python-asn1crypto:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-asn1crypto:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_asn1crypto:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_asn1crypto:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbond_project:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbond_project:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbondproject:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbondproject:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:will_project:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:will_project:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:willproject:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:willproject:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:asn1crypto:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:asn1crypto:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-asn1crypto:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_asn1crypto:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbond_project:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbond:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbond:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbondproject:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:will_project:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:will:python-asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:will:python_asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:willproject:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:asn1crypto:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:wbond:asn1crypto:1.5.1:*:*:*:*:*:*:*', 'cpe:2.3:a:will:asn1crypto:1.5.1:*:*:*:*:*:*:*']",wbond ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sympy,1.12,BSD,PYTHON,"['cpe:2.3:a:sympy_development_team_project:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_team_project:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_teamproject:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_teamproject:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_team_project:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_team:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_team:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_teamproject:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_development_team:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_project:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_project:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sympy:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sympy:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sympy:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sympy:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympyproject:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympyproject:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy_project:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sympy:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sympy:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy:python-sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy:python_sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympyproject:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:sympy:1.12:*:*:*:*:*:*:*', 'cpe:2.3:a:sympy:sympy:1.12:*:*:*:*:*:*:*']",SymPy development team ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tblib,2.0.0,BSD-2-Clause,PYTHON,"['cpe:2.3:a:contact_project:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tblib:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tblib:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tblib:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tblib:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tblib:tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tblib:tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tblib:python-tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tblib:python_tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tblib:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:tblib:tblib:2.0.0:*:*:*:*:*:*:*']",Ionel Cristian Mărieș ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +threadpoolctl,3.2.0,BSD-3-Clause,PYTHON,"['cpe:2.3:a:thomas_moreau_2010_project:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010_project:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010project:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010project:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_project:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_project:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-threadpoolctl:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-threadpoolctl:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_threadpoolctl:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_threadpoolctl:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreauproject:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreauproject:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010_project:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas-moreau-2010:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas-moreau-2010:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010project:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_project:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-threadpoolctl:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_threadpoolctl:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreauproject:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:threadpoolctl:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:threadpoolctl:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas-moreau-2010:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau_2010:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:thomas_moreau:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:threadpoolctl:threadpoolctl:3.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:threadpoolctl:3.2.0:*:*:*:*:*:*:*']",Thomas Moreau ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +locket,1.0.0,BSD-2-Clause,PYTHON,"['cpe:2.3:a:michael_williamson_project:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamson_project:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamsonproject:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamsonproject:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamson_project:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamson:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamson:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamsonproject:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-locket:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-locket:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_locket:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_locket:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_project:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_project:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:michael_williamson:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mikeproject:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mikeproject:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:locket:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:locket:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-locket:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_locket:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_project:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike:python-locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike:python_locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mikeproject:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:locket:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:locket:1.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike:locket:1.0.0:*:*:*:*:*:*:*']",Michael Williamson ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +lz4,4.3.2,Unknown,PYTHON,"['cpe:2.3:a:jonathan_underwood_project:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwood_project:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwoodproject:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwoodproject:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwood_project:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan-underwood:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan-underwood:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwood:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwood:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwoodproject:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan-underwood:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_underwood:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-lz4:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-lz4:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_lz4:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_lz4:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:lz4:python-lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:lz4:python_lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-lz4:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_lz4:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:lz4:4.3.2:*:*:*:*:*:*:*', 'cpe:2.3:a:lz4:lz4:4.3.2:*:*:*:*:*:*:*']",Jonathan Underwood ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +markdown-it-py,3.0.0,Unknown,PYTHON,"['cpe:2.3:a:chris_sewell_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pluggy,1.3.0,MIT,PYTHON,"['cpe:2.3:a:holger_krekel_project:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel_project:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekelproject:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekelproject:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel_project:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_project:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_project:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekelproject:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holgerproject:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holgerproject:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pluggy:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pluggy:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pluggy:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pluggy:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_project:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger_krekel:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holgerproject:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pluggy:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pluggy:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pluggy:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pluggy:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:holger:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pluggy:pluggy:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pluggy:1.3.0:*:*:*:*:*:*:*']",Holger Krekel ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +scikit-learn,1.2.2,new BSD,PYTHON,"['cpe:2.3:a:python-scikit-learn:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit-learn:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit_learn:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit_learn:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit-learn:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit-learn:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit_learn:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit_learn:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit-learn:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit-learn:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit_learn:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit_learn:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-scikit:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_scikit:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit:python-scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit:python_scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit-learn:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit-learn:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit_learn:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit_learn:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:scikit_learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit:scikit-learn:1.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:scikit:scikit_learn:1.2.2:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pyOpenSSL,23.2.0,"Apache License, Version 2.0",PYTHON,"['cpe:2.3:a:pyopenssl_developers_project:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers_project:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developersproject:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developersproject:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev_project:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev_project:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_devproject:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_devproject:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers_project:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developersproject:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev_project:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography-dev:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography-dev:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_devproject:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyOpenSSL:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyOpenSSL:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyOpenSSL:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyOpenSSL:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography-dev:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyOpenSSL:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyOpenSSL:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyOpenSSL:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyOpenSSL:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyOpenSSL:pyOpenSSL:23.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pyOpenSSL:23.2.0:*:*:*:*:*:*:*']",The pyOpenSSL developers ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pyOpenSSL,23.3.0,"Apache License, Version 2.0",PYTHON,"['cpe:2.3:a:pyopenssl_developers_project:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers_project:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developersproject:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developersproject:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev_project:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev_project:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_devproject:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_devproject:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers_project:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developersproject:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev_project:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography-dev:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography-dev:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_devproject:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyOpenSSL:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyOpenSSL:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyOpenSSL:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyOpenSSL:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyopenssl_developers:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography-dev:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:cryptography_dev:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyOpenSSL:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyOpenSSL:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyOpenSSL:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyOpenSSL:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyOpenSSL:pyOpenSSL:23.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pyOpenSSL:23.3.0:*:*:*:*:*:*:*']",The pyOpenSSL developers ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pyarrow,11.0.0,"Apache License, Version 2.0",PYTHON,"['cpe:2.3:a:python-pyarrow:python-pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyarrow:python_pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyarrow:python-pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyarrow:python_pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyarrow:python-pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyarrow:python_pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pyarrow:pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pyarrow:pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pyarrow:pyarrow:11.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pyarrow:11.0.0:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libunistring2,1.0-1,FreeSoftware GFDL-1.2 GFDL-1.2+ GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL-3 LGPL-3+ MIT,dpkg,['cpe:2.3:a:libunistring2:libunistring2:1.0-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libuuid1,2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,['cpe:2.3:a:libuuid1:libuuid1:2.37.2-4ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libxxhash0,0.8.1-1,BSD-2-clause GPL-2,dpkg,['cpe:2.3:a:libxxhash0:libxxhash0:0.8.1-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libzstd1,1.4.8+dfsg-3build1,BSD-3-clause Expat GPL-2 zlib,dpkg,['cpe:2.3:a:libzstd1:libzstd1:1.4.8\\+dfsg-3build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +linux-libc-dev,5.15.0-89.99,GPL-2,dpkg,"['cpe:2.3:a:linux-libc-dev:linux-libc-dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux-libc-dev:linux_libc_dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux_libc_dev:linux-libc-dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux_libc_dev:linux_libc_dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux-libc:linux-libc-dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux-libc:linux_libc_dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux_libc:linux-libc-dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux_libc:linux_libc_dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux:linux-libc-dev:5.15.0-89.99:*:*:*:*:*:*:*', 'cpe:2.3:a:linux:linux_libc_dev:5.15.0-89.99:*:*:*:*:*:*:*']",Ubuntu Kernel Team (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +login,1:4.8.1-2ubuntu2.1,GPL-2,dpkg,['cpe:2.3:a:login:login:1\\:4.8.1-2ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +logsave,1.46.5-2ubuntu1.1,GPL-2 LGPL-2,dpkg,['cpe:2.3:a:logsave:logsave:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +lsb-base,11.1.0ubuntu4,BSD-3-clause GPL-2,dpkg,"['cpe:2.3:a:lsb-base:lsb-base:11.1.0ubuntu4:*:*:*:*:*:*:*', 'cpe:2.3:a:lsb-base:lsb_base:11.1.0ubuntu4:*:*:*:*:*:*:*', 'cpe:2.3:a:lsb_base:lsb-base:11.1.0ubuntu4:*:*:*:*:*:*:*', 'cpe:2.3:a:lsb_base:lsb_base:11.1.0ubuntu4:*:*:*:*:*:*:*', 'cpe:2.3:a:lsb:lsb-base:11.1.0ubuntu4:*:*:*:*:*:*:*', 'cpe:2.3:a:lsb:lsb_base:11.1.0ubuntu4:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +lto-disabled-list,24,GPL-2 GPL-2+,dpkg,"['cpe:2.3:a:lto-disabled-list:lto-disabled-list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto-disabled-list:lto_disabled_list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto_disabled_list:lto-disabled-list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto_disabled_list:lto_disabled_list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto-disabled:lto-disabled-list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto-disabled:lto_disabled_list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto_disabled:lto-disabled-list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto_disabled:lto_disabled_list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto:lto-disabled-list:24:*:*:*:*:*:*:*', 'cpe:2.3:a:lto:lto_disabled_list:24:*:*:*:*:*:*:*']",Matthias Klose (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +make,4.3-4.1build1,GPL-3 GPL-3+,dpkg,['cpe:2.3:a:make:make:4.3-4.1build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mawk,1.3.4.20200120-3,GPL-2,dpkg,['cpe:2.3:a:mawk:mawk:1.3.4.20200120-3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +websockets,12.0,BSD-3-Clause,PYTHON,"['cpe:2.3:a:aymeric_augustin_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mount,2.37.2-4ubuntu3,BSD-2-clause BSD-3-clause BSD-4-clause GPL-2 GPL-2+ GPL-3 GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ MIT public-domain,dpkg,['cpe:2.3:a:mount:mount:2.37.2-4ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pycosat,0.6.4,MIT,PYTHON,"['cpe:2.3:a:ilan_schnell_project:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnell_project:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnellproject:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnellproject:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycosat:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycosat:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycosat:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycosat:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnell_project:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_project:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_project:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnell:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnell:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnellproject:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilanproject:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilanproject:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:pycosat:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:pycosat:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycosat:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycosat:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_project:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan_schnell:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan:python-pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan:python_pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilanproject:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:pycosat:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pycosat:0.6.4:*:*:*:*:*:*:*', 'cpe:2.3:a:ilan:pycosat:0.6.4:*:*:*:*:*:*:*']",Ilan Schnell ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +wheel,0.41.2,Unknown,PYTHON,"['cpe:2.3:a:daniel_holth_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pycparser,2.21,BSD,PYTHON,"['cpe:2.3:a:eli_bendersky_project:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky_project:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_benderskyproject:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_benderskyproject:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycparser:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycparser:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycparser:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycparser:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky_project:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben_project:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben_project:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_benderskyproject:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:elibenproject:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:elibenproject:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:pycparser:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:pycparser:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycparser:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycparser:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben_project:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:elibenproject:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:pycparser:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pycparser:2.21:*:*:*:*:*:*:*']",Eli Bendersky ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pycparser,2.21,BSD,PYTHON,"['cpe:2.3:a:eli_bendersky_project:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky_project:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_benderskyproject:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_benderskyproject:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycparser:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycparser:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycparser:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycparser:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky_project:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben_project:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben_project:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_benderskyproject:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:elibenproject:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:elibenproject:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:pycparser:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:pycparser:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pycparser:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pycparser:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben_project:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eli_bendersky:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:elibenproject:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:pycparser:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:eliben:pycparser:2.21:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pycparser:2.21:*:*:*:*:*:*:*']",Eli Bendersky ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +wheel,0.42.0,Unknown,PYTHON,"['cpe:2.3:a:daniel_holth_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pynvml,11.4.1,BSD,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamora_project:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamora_project:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamoraproject:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamoraproject:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pynvml:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pynvml:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pynvml:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pynvml:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamora_project:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamora:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamora:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamoraproject:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pynvml:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pynvml:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pynvml:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pynvml:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:rzamora:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pynvml:pynvml:11.4.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pynvml:11.4.1:*:*:*:*:*:*:*']",NVIDIA Corporation ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +zict,3.0.0,BSD,PYTHON,"['cpe:2.3:a:python-zict:python-zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zict:python_zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zict:python-zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zict:python_zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zict:zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zict:zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zict:python-zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zict:python_zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:zict:3.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zict:zict:3.0.0:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pyparsing,3.1.1,Unknown,PYTHON,"['cpe:2.3:a:paul_mcguire_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +python-dateutil,2.8.2,Dual License,PYTHON,"['cpe:2.3:a:gustavo_niemeyer_project:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_niemeyer_project:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_niemeyerproject:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_niemeyerproject:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_niemeyer:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_niemeyer:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_project:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo_project:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dateutil:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-dateutil:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dateutil:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_dateutil:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavoproject:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavoproject:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gustavo:python_dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-dateutil:2.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_dateutil:2.8.2:*:*:*:*:*:*:*']",Gustavo Niemeyer ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +zipp,3.17.0,Unknown,PYTHON,"['cpe:2.3:a:jason_r__coombs_project:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zipp:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zipp:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zipp:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zipp:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zipp:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zipp:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zipp:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zipp:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zipp:zipp:3.17.0:*:*:*:*:*:*:*']",Jason R. Coombs ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +zipp,3.17.0,Unknown,PYTHON,"['cpe:2.3:a:jason_r__coombs_project:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs_project:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombsproject:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zipp:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zipp:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zipp:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zipp:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jason_r__coombs:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco_project:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaracoproject:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zipp:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zipp:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zipp:python-zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zipp:python_zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jaraco:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:zipp:3.17.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zipp:zipp:3.17.0:*:*:*:*:*:*:*']",Jason R. Coombs ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +zstandard,0.19.0,BSD,PYTHON,"['cpe:2.3:a:gregory_szorc_project:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorc_project:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorcproject:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorcproject:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zstandard:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zstandard:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zstandard:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zstandard:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorc_project:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory-szorc:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory-szorc:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorc:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorc:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorcproject:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-zstandard:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_zstandard:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zstandard:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zstandard:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory-szorc:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:gregory_szorc:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:zstandard:zstandard:0.19.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:zstandard:0.19.0:*:*:*:*:*:*:*']",Gregory Szorc ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +python,3.10.12,N/A,BINARY,"['cpe:2.3:a:python_software_foundation:python:3.10.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.12:*:*:*:*:*:*:*']",N/A,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +python,3.10.12,N/A,BINARY,"['cpe:2.3:a:python_software_foundation:python:3.10.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.12:*:*:*:*:*:*:*']",N/A,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +python,3.10.13,N/A,BINARY,"['cpe:2.3:a:python_software_foundation:python:3.10.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.13:*:*:*:*:*:*:*']",N/A,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +configparser,5.3.0,Unknown,PYTHON,"['cpe:2.3:a:python-configparser:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-configparser:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_configparser:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_configparser:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukasz_project:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukasz_project:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukaszproject:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukaszproject:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:configparser:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:configparser:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-configparser:configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_configparser:configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukasz_project:configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukasz:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukasz:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukaszproject:configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:configparser:configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lukasz:configparser:5.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:configparser:5.3.0:*:*:*:*:*:*:*']",Łukasz Langa ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +numpy,1.26.2,"Copyright (c) 2005-2023, NumPy Developers. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:travis_e__oliphant_et_al__project:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al__project:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al_project:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al_project:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al__project:numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al_:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al_:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al_project:numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:travis_e__oliphant_et_al_:numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numpy:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numpy:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numpy:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numpy:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:numpy:python-numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:numpy:python_numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numpy:numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numpy:numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:numpy:1.26.2:*:*:*:*:*:*:*', 'cpe:2.3:a:numpy:numpy:1.26.2:*:*:*:*:*:*:*']",Travis E. Oliphant et al.,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +numpydoc,1.4.0,BSD,PYTHON,"['cpe:2.3:a:pauli_virtanen_and_others_project:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_others_project:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_othersproject:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_othersproject:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_others_project:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_others:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_others:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_othersproject:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pauli_virtanen_and_others:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numpydoc:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numpydoc:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numpydoc:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numpydoc:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pav_project:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pav_project:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pavproject:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pavproject:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:numpydoc:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:numpydoc:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-numpydoc:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_numpydoc:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pav_project:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pav:python-numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pav:python_numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pavproject:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:numpydoc:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:numpydoc:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:pav:numpydoc:1.4.0:*:*:*:*:*:*:*']",Pauli Virtanen and others ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +nvtabular,23.6.0,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nvtabular:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nvtabular:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nvtabular:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nvtabular:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvtabular:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvtabular:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nvtabular:nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nvtabular:nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvtabular:nvtabular:23.6.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:nvtabular:23.6.0:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +nvtx,0.2.8,Apache 2.0,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nvtx:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nvtx:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nvtx:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nvtx:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvtx:python-nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvtx:python_nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python-nvtx:nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python_nvtx:nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:python:nvtx:0.2.8:*:*:*:*:*:*:*', 'cpe:2.3:a:nvtx:nvtx:0.2.8:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +oauthlib,3.2.2,BSD,PYTHON,"['cpe:2.3:a:oauthlib_community_project:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_community_project:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_communityproject:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_communityproject:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_community_project:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_community:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_community:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_communityproject:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-oauthlib:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-oauthlib:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_oauthlib:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_oauthlib:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idan_project:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idan_project:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idanproject:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idanproject:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib_community:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-oauthlib:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_oauthlib:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idan_project:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idan:python-oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idan:python_oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idanproject:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:oauthlib:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:oauthlib:3.2.2:*:*:*:*:*:*:*', 'cpe:2.3:a:idan:oauthlib:3.2.2:*:*:*:*:*:*:*']",The OAuthlib Community ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +alembic,1.13.0,MIT,PYTHON,"['cpe:2.3:a:mike_bayer_project:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer_project:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp_project:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp_project:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mpproject:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mpproject:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-alembic:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-alembic:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_alembic:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_alembic:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer_project:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp_project:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:alembic:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:alembic:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-mp:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-mp:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mpproject:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-alembic:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_alembic:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:alembic:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-mp:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp:alembic:1.13.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:alembic:1.13.0:*:*:*:*:*:*:*']",Mike Bayer ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpam-modules,1.4.0-11ubuntu2.3,GPL,dpkg,"['cpe:2.3:a:libpam-modules:libpam-modules:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam-modules:libpam_modules:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_modules:libpam-modules:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_modules:libpam_modules:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam:libpam-modules:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam:libpam_modules:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpam-modules-bin,1.4.0-11ubuntu2.3,GPL,dpkg,"['cpe:2.3:a:libpam-modules-bin:libpam-modules-bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam-modules-bin:libpam_modules_bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_modules_bin:libpam-modules-bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_modules_bin:libpam_modules_bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam-modules:libpam-modules-bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam-modules:libpam_modules_bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_modules:libpam-modules-bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_modules:libpam_modules_bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam:libpam-modules-bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam:libpam_modules_bin:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpam-runtime,1.4.0-11ubuntu2.3,GPL,dpkg,"['cpe:2.3:a:libpam-runtime:libpam-runtime:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam-runtime:libpam_runtime:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_runtime:libpam-runtime:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam_runtime:libpam_runtime:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam:libpam-runtime:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libpam:libpam_runtime:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpam0g,1.4.0-11ubuntu2.3,GPL,dpkg,['cpe:2.3:a:libpam0g:libpam0g:1.4.0-11ubuntu2.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpcre2-8-0,10.39-3ubuntu0.1,Unknown,dpkg,"['cpe:2.3:a:libpcre2-8-0:libpcre2-8-0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2-8-0:libpcre2_8_0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2_8_0:libpcre2-8-0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2_8_0:libpcre2_8_0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2-8:libpcre2-8-0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2-8:libpcre2_8_0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2_8:libpcre2-8-0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2_8:libpcre2_8_0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2:libpcre2-8-0:10.39-3ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libpcre2:libpcre2_8_0:10.39-3ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpcre3,2:8.39-13ubuntu0.22.04.1,Unknown,dpkg,['cpe:2.3:a:libpcre3:libpcre3:2\\:8.39-13ubuntu0.22.04.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpcsclite1,1.9.5-3ubuntu1,BSD-3-clause GPL-3 GPL-3+ ISC,dpkg,['cpe:2.3:a:libpcsclite1:libpcsclite1:1.9.5-3ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libperl5.34,5.34.0-3ubuntu1.3,"Artistic Artistic-2 Artistic-dist BSD-3-clause BSD-3-clause-GENERIC BSD-3-clause-with-weird-numbering BSD-4-clause-POWERDOG BZIP DONT-CHANGE-THE-GPL Expat GPL-1 GPL-1+ GPL-2 GPL-2+ GPL-3+-WITH-BISON-EXCEPTION HSIEH-BSD HSIEH-DERIVATIVE LGPL-2.1 REGCOMP REGCOMP, RRA-KEEP-THIS-NOTICE SDBM-PUBLIC-DOMAIN TEXT-TABS Unicode ZLIB",dpkg,['cpe:2.3:a:libperl5.34:libperl5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpng16-16,1.6.37-3build5,Apache-2.0 BSD-3-clause BSD-like-with-advertising-clause GPL-2 GPL-2+ expat libpng,dpkg,"['cpe:2.3:a:libpng16-16:libpng16-16:1.6.37-3build5:*:*:*:*:*:*:*', 'cpe:2.3:a:libpng16-16:libpng16_16:1.6.37-3build5:*:*:*:*:*:*:*', 'cpe:2.3:a:libpng16_16:libpng16-16:1.6.37-3build5:*:*:*:*:*:*:*', 'cpe:2.3:a:libpng16_16:libpng16_16:1.6.37-3build5:*:*:*:*:*:*:*', 'cpe:2.3:a:libpng16:libpng16-16:1.6.37-3build5:*:*:*:*:*:*:*', 'cpe:2.3:a:libpng16:libpng16_16:1.6.37-3build5:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libprocps8,2:3.3.17-6ubuntu2.1,GPL-2 GPL-2.0+ LGPL-2 LGPL-2.0+ LGPL-2.1 LGPL-2.1+,dpkg,['cpe:2.3:a:libprocps8:libprocps8:2\\:3.3.17-6ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libpsl5,0.21.0-1.2build2,Chromium MIT,dpkg,['cpe:2.3:a:libpsl5:libpsl5:0.21.0-1.2build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libquadmath0,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libquadmath0:libquadmath0:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libreadline8,8.1.2-1,GFDL GPL-3,dpkg,['cpe:2.3:a:libreadline8:libreadline8:8.1.2-1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +psutil,5.9.5,BSD-3-Clause,PYTHON,"['cpe:2.3:a:giampaolo_rodola_project:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola_project:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodolaproject:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodolaproject:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola_project:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola_project:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola_project:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodolaproject:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodolaproject:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodolaproject:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-psutil:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-psutil:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_psutil:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_psutil:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola_project:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:giampaolo_rodola:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g-rodola:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g-rodola:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodolaproject:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:psutil:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:psutil:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python-psutil:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python_psutil:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g-rodola:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:g_rodola:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:psutil:psutil:5.9.5:*:*:*:*:*:*:*', 'cpe:2.3:a:python:psutil:5.9.5:*:*:*:*:*:*:*']",Giampaolo Rodola ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gitdb,4.0.11,BSD License,PYTHON,"['cpe:2.3:a:sebastian_thiel_project:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel_project:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thielproject:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thielproject:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel_project:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thielproject:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gitdb:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gitdb:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gitdb:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gitdb:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:gitdb:python-gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:gitdb:python_gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gitdb:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gitdb:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:python:gitdb:4.0.11:*:*:*:*:*:*:*', 'cpe:2.3:a:gitdb:gitdb:4.0.11:*:*:*:*:*:*:*']",Sebastian Thiel ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gmpy2,2.1.2,LGPL-3.0+,PYTHON,"['cpe:2.3:a:case_van_horsen_project:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsen_project:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsenproject:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsenproject:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsen_project:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsen:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsen:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsenproject:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevh_project:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevh_project:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevhproject:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevhproject:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gmpy2:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gmpy2:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gmpy2:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gmpy2:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:case_van_horsen:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevh_project:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevh:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevh:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevhproject:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gmpy2:python-gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gmpy2:python_gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-gmpy2:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_gmpy2:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:casevh:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:gmpy2:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:gmpy2:gmpy2:2.1.2:*:*:*:*:*:*:*']",Case Van Horsen ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +importlib-resources,6.1.1,Unknown,PYTHON,"['cpe:2.3:a:python-importlib-resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib-resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib_resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw_project:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsawproject:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib-resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib_resources:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-importlib:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_importlib:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_project:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:python-importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:python_importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry_warsaw:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barryproject:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:importlib:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:importlib_resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:importlib-resources:6.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:barry:importlib_resources:6.1.1:*:*:*:*:*:*:*']",Barry Warsaw ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +itsdangerous,2.1.2,BSD-3-Clause,PYTHON,"['cpe:2.3:a:armin_ronacher_project:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-itsdangerous:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-itsdangerous:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_itsdangerous:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_itsdangerous:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher_project:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacherproject:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:itsdangerous:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:itsdangerous:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-itsdangerous:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_itsdangerous:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin-ronacher:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:armin_ronacher:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:itsdangerous:itsdangerous:2.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:itsdangerous:2.1.2:*:*:*:*:*:*:*']",Armin Ronacher ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +joblib,1.3.2,BSD 3-Clause,PYTHON,"['cpe:2.3:a:gael_varoquaux_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +joblib,1.3.2,BSD 3-Clause,PYTHON,"['cpe:2.3:a:gael_varoquaux_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +json5,0.9.14,Apache,PYTHON,"['cpe:2.3:a:dirk_pranke_project:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_pranke_project:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_prankeproject:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_prankeproject:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dpranke_project:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dpranke_project:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dprankeproject:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dprankeproject:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_pranke_project:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python-json5:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python-json5:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python_json5:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python_json5:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_pranke:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_pranke:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_prankeproject:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dpranke_project:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dpranke:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dpranke:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dprankeproject:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:json5:python-json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:json5:python_json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python-json5:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python_json5:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dirk_pranke:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:dpranke:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:python:json5:0.9.14:*:*:*:*:*:*:*', 'cpe:2.3:a:json5:json5:0.9.14:*:*:*:*:*:*:*']",Dirk Pranke ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jsonpatch,1.32,Modified BSD License,PYTHON,"['cpe:2.3:a:python-jsonpatch:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonpatch:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonpatch:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonpatch:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_project:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_project:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefanproject:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefanproject:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonpatch:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonpatch:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonpatch:jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonpatch:jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_project:jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan:python-jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan:python_jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefanproject:jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonpatch:jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python:jsonpatch:1.32:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan:jsonpatch:1.32:*:*:*:*:*:*:*']",Stefan Kögl ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libstdc++-11-dev,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,"['cpe:2.3:a:libstdc\\+\\+-11-dev:libstdc\\+\\+-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+-11-dev:libstdc\\+\\+_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+_11_dev:libstdc\\+\\+-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+_11_dev:libstdc\\+\\+_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+-11:libstdc\\+\\+-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+-11:libstdc\\+\\+_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+_11:libstdc\\+\\+-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+_11:libstdc\\+\\+_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+:libstdc\\+\\+-11-dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*', 'cpe:2.3:a:libstdc\\+\\+:libstdc\\+\\+_11_dev:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*']",Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libstdc++6,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libstdc\\+\\+6:libstdc\\+\\+6:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libsystemd0,249.11-0ubuntu3.11,CC0-1.0 Expat GPL-2 GPL-2+ LGPL-2.1 LGPL-2.1+ public-domain,dpkg,['cpe:2.3:a:libsystemd0:libsystemd0:249.11-0ubuntu3.11:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libtasn1-6,4.18.0-4build1,GFDL-1.3 GPL-3 LGPL LGPL-2.1,dpkg,"['cpe:2.3:a:libtasn1-6:libtasn1-6:4.18.0-4build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtasn1-6:libtasn1_6:4.18.0-4build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtasn1_6:libtasn1-6:4.18.0-4build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtasn1_6:libtasn1_6:4.18.0-4build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtasn1:libtasn1-6:4.18.0-4build1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtasn1:libtasn1_6:4.18.0-4build1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libtinfo6,6.3-2ubuntu0.1,BSD-3-clause MIT/X11 X11,dpkg,['cpe:2.3:a:libtinfo6:libtinfo6:6.3-2ubuntu0.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libtirpc-common,1.3.2-2ubuntu0.1,BSD-3-Clause GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libtirpc-common:libtirpc-common:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc-common:libtirpc_common:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc_common:libtirpc-common:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc_common:libtirpc_common:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc:libtirpc-common:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc:libtirpc_common:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libtirpc-dev,1.3.2-2ubuntu0.1,BSD-3-Clause GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libtirpc-dev:libtirpc-dev:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc-dev:libtirpc_dev:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc_dev:libtirpc-dev:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc_dev:libtirpc_dev:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc:libtirpc-dev:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:libtirpc:libtirpc_dev:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libtirpc3,1.3.2-2ubuntu0.1,BSD-3-Clause GPL-2 LGPL-2.1,dpkg,['cpe:2.3:a:libtirpc3:libtirpc3:1.3.2-2ubuntu0.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libtsan0,11.4.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libtsan0:libtsan0:11.4.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libubsan1,12.3.0-1ubuntu1~22.04,Artistic GFDL-1.2 GPL GPL-2 GPL-3 LGPL,dpkg,['cpe:2.3:a:libubsan1:libubsan1:12.3.0-1ubuntu1\\~22.04:*:*:*:*:*:*:*'],Ubuntu Core developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libudev1,249.11-0ubuntu3.11,CC0-1.0 Expat GPL-2 GPL-2+ LGPL-2.1 LGPL-2.1+ public-domain,dpkg,['cpe:2.3:a:libudev1:libudev1:249.11-0ubuntu3.11:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +SQLAlchemy,2.0.0,MIT,PYTHON,"['cpe:2.3:a:mike_bayer_project:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer_project:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-SQLAlchemy:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-SQLAlchemy:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_SQLAlchemy:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_SQLAlchemy:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp_project:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp_project:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mpproject:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mpproject:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer_project:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:SQLAlchemy:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:SQLAlchemy:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayerproject:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-SQLAlchemy:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_SQLAlchemy:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp_project:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-mp:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-mp:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mpproject:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:SQLAlchemy:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_bayer:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike-mp:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mike_mp:SQLAlchemy:2.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:SQLAlchemy:2.0.0:*:*:*:*:*:*:*']",Mike Bayer ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +SciPy,1.11.4,"Copyright (c) 2001-2002 Enthought, Inc. 2003-2023, SciPy Developers. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:python-SciPy:python-SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-SciPy:python_SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_SciPy:python-SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_SciPy:python_SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:SciPy:python-SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:SciPy:python_SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-SciPy:SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_SciPy:SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:SciPy:1.11.4:*:*:*:*:*:*:*', 'cpe:2.3:a:SciPy:SciPy:1.11.4:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Sphinx,7.2.6,Unknown,PYTHON,"['cpe:2.3:a:georg_brandl_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +Werkzeug,3.0.1,Unknown,PYTHON,"['cpe:2.3:a:python-Werkzeug:python-Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Werkzeug:python_Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Werkzeug:python-Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Werkzeug:python_Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:Werkzeug:python-Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:Werkzeug:python_Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-Werkzeug:Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_Werkzeug:Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:Werkzeug:Werkzeug:3.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:Werkzeug:3.0.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +absl-py,1.4.0,Apache 2.0,PYTHON,"['cpe:2.3:a:abseil_authors_project:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors_project:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authorsproject:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authorsproject:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors_project:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors_project:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authorsproject:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authorsproject:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl-py:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl-py:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl_py:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl_py:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:abseil_authors:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl-py:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl-py:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl_py:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl_py:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl-py:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl-py:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl_py:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl_py:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl:python-absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl:python_absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-absl:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_absl:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl-py:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl-py:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl_py:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl_py:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:absl_py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl:absl-py:1.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:absl:absl_py:1.4.0:*:*:*:*:*:*:*']",The Abseil Authors,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +alabaster,0.7.13,Unknown,PYTHON,"['cpe:2.3:a:jeff_forcier_project:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcier_project:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcierproject:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcierproject:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python-alabaster:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python-alabaster:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python_alabaster:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python_alabaster:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcier_project:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcier:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcier:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcierproject:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_project:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_project:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffproject:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffproject:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:alabaster:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:alabaster:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python-alabaster:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python_alabaster:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_forcier:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_project:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff:python-alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff:python_alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeffproject:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:alabaster:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:alabaster:0.7.13:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff:alabaster:0.7.13:*:*:*:*:*:*:*']",Jeff Forcier ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jsonpointer,2.0,Modified BSD License,PYTHON,"['cpe:2.3:a:python-jsonpointer:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonpointer:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonpointer:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonpointer:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_project:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_project:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefanproject:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefanproject:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonpointer:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonpointer:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonpointer:jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonpointer:jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan_project:jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan:python-jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan:python_jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefanproject:jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonpointer:jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:jsonpointer:2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stefan:jsonpointer:2.0:*:*:*:*:*:*:*']",Stefan Kögl ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +smmap,5.0.0,BSD,PYTHON,"['cpe:2.3:a:sebastian_thiel_project:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel_project:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thielproject:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thielproject:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel_project:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thielproject:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-smmap:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-smmap:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_smmap:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_smmap:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo_project:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimoproject:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sebastian_thiel:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-smmap:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_smmap:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:smmap:python-smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:smmap:python_smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:byronimo:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:smmap:5.0.0:*:*:*:*:*:*:*', 'cpe:2.3:a:smmap:smmap:5.0.0:*:*:*:*:*:*:*']",Sebastian Thiel ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sniffio,1.3.0,MIT OR Apache-2.0,PYTHON,"['cpe:2.3:a:nathaniel_j__smith_project:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smith_project:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smithproject:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smithproject:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smith_project:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smith:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smith:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smithproject:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sniffio:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sniffio:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sniffio:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sniffio:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nathaniel_j__smith:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njs_project:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njs_project:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njsproject:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njsproject:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sniffio:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sniffio:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sniffio:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sniffio:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njs_project:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njs:python-sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njs:python_sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njsproject:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sniffio:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:sniffio:1.3.0:*:*:*:*:*:*:*', 'cpe:2.3:a:njs:sniffio:1.3.0:*:*:*:*:*:*:*']",Nathaniel J. Smith ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +snowballstemmer,2.2.0,BSD-3-Clause,PYTHON,"['cpe:2.3:a:snowball_developers_project:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developers_project:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developersproject:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developersproject:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discuss_project:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discuss_project:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discussproject:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discussproject:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-snowballstemmer:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-snowballstemmer:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_snowballstemmer:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_snowballstemmer:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developers_project:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developers:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developers:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developersproject:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discuss_project:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball-discuss:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball-discuss:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discuss:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discuss:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discussproject:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-snowballstemmer:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_snowballstemmer:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowballstemmer:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowballstemmer:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_developers:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball-discuss:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowball_discuss:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:snowballstemmer:snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_snowballstemmer:2.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:snowballstemmer:2.2.0:*:*:*:*:*:*:*']",Snowball Developers ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sortedcontainers,2.4.0,Apache 2.0,PYTHON,"['cpe:2.3:a:python-sortedcontainers:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sortedcontainers:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sortedcontainers:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sortedcontainers:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenks_project:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenks_project:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenksproject:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenksproject:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-sortedcontainers:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_sortedcontainers:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sortedcontainers:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sortedcontainers:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenks_project:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenks:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenks:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenksproject:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:sortedcontainers:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:grant_jenks:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:sortedcontainers:2.4.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:sortedcontainers:2.4.0:*:*:*:*:*:*:*']",Grant Jenks ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +soupsieve,2.5,Unknown,PYTHON,"['cpe:2.3:a:isaac_muse_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +toolz,0.12.0,BSD,PYTHON,"['cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md_project:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md_project:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_mdproject:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_mdproject:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md_project:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_mdproject:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-toolz:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-toolz:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_toolz:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_toolz:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-toolz:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_toolz:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:toolz:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:toolz:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:toolz:toolz:0.12.0:*:*:*:*:*:*:*']",https://raw.github.com/pytoolz/toolz/master/AUTHORS.md,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +toolz,0.12.0,BSD,PYTHON,"['cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md_project:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md_project:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_mdproject:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_mdproject:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md_project:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_mdproject:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:https\\:\\/\\/raw_github_com\\/pytoolz\\/toolz\\/master\\/authors_md:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-toolz:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-toolz:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_toolz:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_toolz:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-toolz:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_toolz:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:toolz:python-toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:toolz:python_toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:toolz:0.12.0:*:*:*:*:*:*:*', 'cpe:2.3:a:toolz:toolz:0.12.0:*:*:*:*:*:*:*']",https://raw.github.com/pytoolz/toolz/master/AUTHORS.md,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +torch,2.0.1,BSD-3,PYTHON,"['cpe:2.3:a:pytorch_team_project:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_team_project:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_teamproject:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_teamproject:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packages_project:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packages_project:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packagesproject:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packagesproject:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_team_project:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-torch:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-torch:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_torch:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_torch:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_team:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_team:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_teamproject:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packages_project:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packages:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packages:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packagesproject:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-torch:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_torch:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:pytorch_team:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:torch:python-torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:torch:python_torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:packages:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:torch:2.0.1:*:*:*:*:*:*:*', 'cpe:2.3:a:torch:torch:2.0.1:*:*:*:*:*:*:*']",PyTorch Team ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tornado,6.3.3,Apache-2.0,PYTHON,"['cpe:2.3:a:python_tornado_project:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornado_project:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornadoproject:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornadoproject:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebook_project:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebook_project:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebookproject:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebookproject:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornado_project:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tornado:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tornado:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornado:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornado:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornadoproject:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebook_project:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebook:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebook:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebookproject:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tornado:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tornado:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:tornado:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:tornado:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:facebook:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:tornado:tornado:6.3.3:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tornado:6.3.3:*:*:*:*:*:*:*']",Facebook ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tqdm,4.66.1,MPL-2.0 AND MIT,PYTHON,"['cpe:2.3:a:python-tqdm:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tqdm:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tqdm:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tqdm:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tqdm:tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tqdm:tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tqdm:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tqdm:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tqdm:tqdm:4.66.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tqdm,4.66.1,MPL-2.0 AND MIT,PYTHON,"['cpe:2.3:a:python-tqdm:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tqdm:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tqdm:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tqdm:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tqdm:tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tqdm:tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tqdm:python-tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tqdm:python_tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tqdm:4.66.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tqdm:tqdm:4.66.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libgnutls30,3.7.3-4ubuntu1.3,Apache-2.0 BSD-3-Clause CC0 Expat GFDL-1.3 GPL GPL-3 GPLv3+ LGPL LGPL-3 LGPLv2.1+ LGPLv3+_or_GPLv2+ The,dpkg,['cpe:2.3:a:libgnutls30:libgnutls30:3.7.3-4ubuntu1.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libharfbuzz0b,2.7.4-1ubuntu3.1,MIT,dpkg,['cpe:2.3:a:libharfbuzz0b:libharfbuzz0b:2.7.4-1ubuntu3.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libhogweed6,3.7.3-1build2,Expat GAP GPL GPL-2 GPL-2+ GPL-3+ LGPL LGPL-2 LGPL-2+ LGPL-3+ public-domain,dpkg,['cpe:2.3:a:libhogweed6:libhogweed6:3.7.3-1build2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mrc,23.11.0,Apache,PYTHON,"['cpe:2.3:a:nvidia_corporation_project:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation_project:mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporationproject:mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:nvidia_corporation:mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mrc:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mrc:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mrc:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mrc:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mrc:python-mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mrc:python_mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mrc:mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mrc:mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:mrc:23.11.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mrc:mrc:23.11.0:*:*:*:*:*:*:*']",NVIDIA Corporation,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libisl23,0.24-2build1,BSD-2-clause LGPL-2 LGPL-2.1+ MIT,dpkg,['cpe:2.3:a:libisl23:libisl23:0.24-2build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +requests-cache,1.1.1,BSD-2-Clause,PYTHON,"['cpe:2.3:a:roman_haritonov_project:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov_project:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonovproject:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonovproject:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests-cache:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests-cache:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests_cache:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests_cache:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov_project:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov_project:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonovproject:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonovproject:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests-cache:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests-cache:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests_cache:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests_cache:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests-cache:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests-cache:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests_cache:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests_cache:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-requests:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_requests:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:roman_haritonov:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests-cache:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests-cache:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests_cache:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests_cache:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:requests:requests_cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:requests-cache:1.1.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:requests_cache:1.1.1:*:*:*:*:*:*:*']",Roman Haritonov,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +msgpack,1.0.7,Apache 2.0,PYTHON,"['cpe:2.3:a:inada_naoki_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libjpeg8,8c-2ubuntu10,LGPL-2.1,dpkg,['cpe:2.3:a:libjpeg8:libjpeg8:8c-2ubuntu10:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +multidict,6.0.4,Apache 2,PYTHON,"['cpe:2.3:a:andrew_svetlov_project:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlov_project:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlovproject:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlovproject:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-multidict:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-multidict:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_multidict:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_multidict:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlov_project:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew-svetlov:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew-svetlov:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlov:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlov:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlovproject:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:multidict:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:multidict:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-multidict:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_multidict:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew-svetlov:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:andrew_svetlov:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:multidict:multidict:6.0.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:multidict:6.0.4:*:*:*:*:*:*:*']",Andrew Svetlov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libjq1,1.6-2.1ubuntu3,CC-BY-3.0 Expat GPL-2 GPL-2.0+ MIT,dpkg,['cpe:2.3:a:libjq1:libjq1:1.6-2.1ubuntu3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +munkres,1.1.4,Apache Software License,PYTHON,"['cpe:2.3:a:brian_clapper_project:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapper_project:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapperproject:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapperproject:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapper_project:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-munkres:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-munkres:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_munkres:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_munkres:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapper:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapper:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapperproject:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmc_project:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmc_project:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmcproject:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmcproject:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:munkres:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:munkres:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python-munkres:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python_munkres:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:brian_clapper:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmc_project:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmc:python-munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmc:python_munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmcproject:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:munkres:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:python:munkres:1.1.4:*:*:*:*:*:*:*', 'cpe:2.3:a:bmc:munkres:1.1.4:*:*:*:*:*:*:*']",Brian Clapper ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +perl-modules-5.34,5.34.0-3ubuntu1.3,"Artistic Artistic-2 Artistic-dist BSD-3-clause BSD-3-clause-GENERIC BSD-3-clause-with-weird-numbering BSD-4-clause-POWERDOG BZIP DONT-CHANGE-THE-GPL Expat GPL-1 GPL-1+ GPL-2 GPL-2+ GPL-3+-WITH-BISON-EXCEPTION HSIEH-BSD HSIEH-DERIVATIVE LGPL-2.1 REGCOMP REGCOMP, RRA-KEEP-THIS-NOTICE SDBM-PUBLIC-DOMAIN TEXT-TABS Unicode ZLIB",dpkg,"['cpe:2.3:a:perl-modules-5.34:perl-modules-5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl-modules-5.34:perl_modules_5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl_modules_5.34:perl-modules-5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl_modules_5.34:perl_modules_5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl-modules:perl-modules-5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl-modules:perl_modules_5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl_modules:perl-modules-5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl_modules:perl_modules_5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl:perl-modules-5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*', 'cpe:2.3:a:perl:perl_modules_5.34:5.34.0-3ubuntu1.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pinentry-curses,1.1.1-1build2,GPL-2 GPL-2+ LGPL-3 LGPL-3+ X11,dpkg,"['cpe:2.3:a:pinentry-curses:pinentry-curses:1.1.1-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:pinentry-curses:pinentry_curses:1.1.1-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:pinentry_curses:pinentry-curses:1.1.1-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:pinentry_curses:pinentry_curses:1.1.1-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:pinentry:pinentry-curses:1.1.1-1build2:*:*:*:*:*:*:*', 'cpe:2.3:a:pinentry:pinentry_curses:1.1.1-1build2:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pkg-config,0.29.2-1ubuntu3,GPL,dpkg,"['cpe:2.3:a:pkg-config:pkg-config:0.29.2-1ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:pkg-config:pkg_config:0.29.2-1ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:pkg_config:pkg-config:0.29.2-1ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:pkg_config:pkg_config:0.29.2-1ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:pkg:pkg-config:0.29.2-1ubuntu3:*:*:*:*:*:*:*', 'cpe:2.3:a:pkg:pkg_config:0.29.2-1ubuntu3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +procps,2:3.3.17-6ubuntu2.1,GPL-2 GPL-2.0+ LGPL-2 LGPL-2.0+ LGPL-2.1 LGPL-2.1+,dpkg,['cpe:2.3:a:procps:procps:2\\:3.3.17-6ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +readline-common,8.1.2-1,GFDL GPL-3,dpkg,"['cpe:2.3:a:readline-common:readline-common:8.1.2-1:*:*:*:*:*:*:*', 'cpe:2.3:a:readline-common:readline_common:8.1.2-1:*:*:*:*:*:*:*', 'cpe:2.3:a:readline_common:readline-common:8.1.2-1:*:*:*:*:*:*:*', 'cpe:2.3:a:readline_common:readline_common:8.1.2-1:*:*:*:*:*:*:*', 'cpe:2.3:a:readline:readline-common:8.1.2-1:*:*:*:*:*:*:*', 'cpe:2.3:a:readline:readline_common:8.1.2-1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +rpcsvc-proto,1.4.2-0ubuntu6,BSD-3-clause GPL-2 GPL-2+-autoconf-exception GPL-3 GPL-3+-autoconf-exception MIT permissive-autoconf-m4 permissive-autoconf-m4-no-warranty permissive-configure permissive-fsf permissive-makefile-in,dpkg,"['cpe:2.3:a:rpcsvc-proto:rpcsvc-proto:1.4.2-0ubuntu6:*:*:*:*:*:*:*', 'cpe:2.3:a:rpcsvc-proto:rpcsvc_proto:1.4.2-0ubuntu6:*:*:*:*:*:*:*', 'cpe:2.3:a:rpcsvc_proto:rpcsvc-proto:1.4.2-0ubuntu6:*:*:*:*:*:*:*', 'cpe:2.3:a:rpcsvc_proto:rpcsvc_proto:1.4.2-0ubuntu6:*:*:*:*:*:*:*', 'cpe:2.3:a:rpcsvc:rpcsvc-proto:1.4.2-0ubuntu6:*:*:*:*:*:*:*', 'cpe:2.3:a:rpcsvc:rpcsvc_proto:1.4.2-0ubuntu6:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sed,4.8-1ubuntu2,GPL-3,dpkg,['cpe:2.3:a:sed:sed:4.8-1ubuntu2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +sensible-utils,0.0.17,All-permissive GPL-2 GPL-2+ configure installsh,dpkg,"['cpe:2.3:a:sensible-utils:sensible-utils:0.0.17:*:*:*:*:*:*:*', 'cpe:2.3:a:sensible-utils:sensible_utils:0.0.17:*:*:*:*:*:*:*', 'cpe:2.3:a:sensible_utils:sensible-utils:0.0.17:*:*:*:*:*:*:*', 'cpe:2.3:a:sensible_utils:sensible_utils:0.0.17:*:*:*:*:*:*:*', 'cpe:2.3:a:sensible:sensible-utils:0.0.17:*:*:*:*:*:*:*', 'cpe:2.3:a:sensible:sensible_utils:0.0.17:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ubuntu-keyring,2021.03.26,GPL,dpkg,"['cpe:2.3:a:ubuntu-keyring:ubuntu-keyring:2021.03.26:*:*:*:*:*:*:*', 'cpe:2.3:a:ubuntu-keyring:ubuntu_keyring:2021.03.26:*:*:*:*:*:*:*', 'cpe:2.3:a:ubuntu_keyring:ubuntu-keyring:2021.03.26:*:*:*:*:*:*:*', 'cpe:2.3:a:ubuntu_keyring:ubuntu_keyring:2021.03.26:*:*:*:*:*:*:*', 'cpe:2.3:a:ubuntu:ubuntu-keyring:2021.03.26:*:*:*:*:*:*:*', 'cpe:2.3:a:ubuntu:ubuntu_keyring:2021.03.26:*:*:*:*:*:*:*']",Dimitri John Ledkov (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jupyter_client,8.6.0,"BSD 3-Clause License + + - Copyright (c) 2001-2015, IPython Development Team + - Copyright (c) 2015-, Jupyter Development Team + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",PYTHON,"['cpe:2.3:a:jupyter_development_team_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libssl3,3.0.2-0ubuntu1.12,Apache-2.0 Artistic GPL-1 GPL-1+,dpkg,['cpe:2.3:a:libssl3:libssl3:3.0.2-0ubuntu1.12:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +attrs,23.1.0,Unknown,PYTHON,"['cpe:2.3:a:hynek_schlawack_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tabulate,0.9.0,MIT,PYTHON,"['cpe:2.3:a:sergey_astanin_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +tensorflow-metadata,1.13.1,Apache 2.0,PYTHON,"['cpe:2.3:a:tensorflow_extended_dev_project:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev_project:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_devproject:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_devproject:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow-metadata:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow-metadata:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow_metadata:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow_metadata:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev_project:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev_project:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-extended-dev:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-extended-dev:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_devproject:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_devproject:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc__project:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc__project:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow-metadata:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow-metadata:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow_metadata:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow_metadata:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-metadata:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-metadata:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_metadata:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_metadata:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_project:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_project:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-extended-dev:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-extended-dev:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_extended_dev:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc__project:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc__project:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-metadata:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow-metadata:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_metadata:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow_metadata:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_project:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_project:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-tensorflow:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_tensorflow:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:google_inc_:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:tensorflow:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tensorflow-metadata:1.13.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:tensorflow_metadata:1.13.1:*:*:*:*:*:*:*']",Google Inc. ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +python,3.10.13,N/A,BINARY,"['cpe:2.3:a:python_software_foundation:python:3.10.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.13:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python:3.10.13:*:*:*:*:*:*:*']",N/A,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +pkginfo,1.9.6,MIT,PYTHON,"['cpe:2.3:a:tres_seaver\\,_agendaless_consulting_project:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consulting_project:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consultingproject:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consultingproject:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consulting_project:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consulting:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consulting:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consultingproject:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tres_seaver\\,_agendaless_consulting:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaver_project:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaver_project:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkginfo:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkginfo:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkginfo:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkginfo:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaverproject:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaverproject:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaver_project:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:pkginfo:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:pkginfo:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python-pkginfo:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python_pkginfo:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaver:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaver:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaverproject:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:pkginfo:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:tseaver:pkginfo:1.9.6:*:*:*:*:*:*:*', 'cpe:2.3:a:python:pkginfo:1.9.6:*:*:*:*:*:*:*']","Tres Seaver, Agendaless Consulting ",nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +platformdirs,4.1.0,Unknown,PYTHON,"['cpe:2.3:a:python-platformdirs:python-platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-platformdirs:python_platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_platformdirs:python-platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_platformdirs:python_platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:platformdirs:python-platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:platformdirs:python_platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-platformdirs:platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_platformdirs:platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:platformdirs:platformdirs:4.1.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:platformdirs:4.1.0:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mamba,1.5.0,Unknown,PYTHON,"['cpe:2.3:a:wolf_vollprecht_project:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht_project:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprechtproject:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprechtproject:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht_project:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf-vollprecht:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf-vollprecht:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprechtproject:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mamba:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mamba:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mamba:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mamba:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf-vollprecht:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mamba:python-mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mamba:python_mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-mamba:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_mamba:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:mamba:1.5.0:*:*:*:*:*:*:*', 'cpe:2.3:a:mamba:mamba:1.5.0:*:*:*:*:*:*:*']",Wolf Vollprecht ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +mdurl,0.1.0,Unknown,PYTHON,"['cpe:2.3:a:taneli_hukkinen_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +ruamel.yaml,0.17.32,MIT license,PYTHON,"['cpe:2.3:a:anthon_van_der_neut_project:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neut_project:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neutproject:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neutproject:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neut_project:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neut_project:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neutproject:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neutproject:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neut_project:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neut:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neut:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neutproject:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ruamel.yaml:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ruamel.yaml:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ruamel.yaml:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ruamel.yaml:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neut_project:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a-van-der-neut:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a-van-der-neut:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neut:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neut:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neutproject:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:anthon_van_der_neut:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python-ruamel.yaml:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python_ruamel.yaml:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:ruamel.yaml:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:ruamel.yaml:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a-van-der-neut:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:a_van_der_neut:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:ruamel.yaml:ruamel.yaml:0.17.32:*:*:*:*:*:*:*', 'cpe:2.3:a:python:ruamel.yaml:0.17.32:*:*:*:*:*:*:*']",Anthon van der Neut ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +setuptools,68.1.2,Unknown,PYTHON,"['cpe:2.3:a:python_packaging_authority_project:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority_project:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authorityproject:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authorityproject:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority_project:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authorityproject:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_packaging_authority:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-setuptools:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-setuptools:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_setuptools:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_setuptools:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig_project:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sigproject:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-setuptools:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_setuptools:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:setuptools:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:setuptools:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils-sig:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:distutils_sig:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:setuptools:setuptools:68.1.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:setuptools:68.1.2:*:*:*:*:*:*:*']",Python Packaging Authority ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jsonschema,4.20.0,MIT,PYTHON,"['cpe:2.3:a:julian\\+jsonschema_project:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_project:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschemaproject:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschemaproject:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_project:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschemaproject:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:jsonschema:4.20.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:jsonschema:4.20.0:*:*:*:*:*:*:*']",Julian Berman ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +jsonschema-specifications,2023.11.2,MIT,PYTHON,"['cpe:2.3:a:julian\\+jsonschema_specifications_project:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications_project:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specificationsproject:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specificationsproject:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications_project:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications_project:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema-specifications:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema-specifications:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specificationsproject:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specificationsproject:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema-specifications:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema-specifications:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema_specifications:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema_specifications:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema-specifications:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema-specifications:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema_specifications:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema_specifications:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema-specifications:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema-specifications:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian\\+jsonschema_specifications:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema-specifications:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema-specifications:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema_specifications:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema_specifications:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema-specifications:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema-specifications:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema_specifications:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema_specifications:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman_project:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_bermanproject:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-jsonschema:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_jsonschema:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:julian_berman:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:jsonschema:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:jsonschema-specifications:2023.11.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:jsonschema_specifications:2023.11.2:*:*:*:*:*:*:*']",Julian Berman ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +urllib3,2.0.4,Unknown,PYTHON,"['cpe:2.3:a:andrey_petrov_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +urllib3,2.1.0,Unknown,PYTHON,"['cpe:2.3:a:andrey_petrov_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +watchdog,2.1.9,Apache License 2.0,PYTHON,"['cpe:2.3:a:yesudeep_mangalapilly_project:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapilly_project:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapillyproject:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapillyproject:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapilly_project:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapilly:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapilly:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapillyproject:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_project:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_project:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-watchdog:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-watchdog:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_watchdog:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_watchdog:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeepproject:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeepproject:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_mangalapilly:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep_project:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python-watchdog:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python_watchdog:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:watchdog:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:watchdog:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeepproject:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:watchdog:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:yesudeep:watchdog:2.1.9:*:*:*:*:*:*:*', 'cpe:2.3:a:python:watchdog:2.1.9:*:*:*:*:*:*:*']",Yesudeep Mangalapilly ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +watchgod,0.8.2,MIT,PYTHON,"['cpe:2.3:a:samuel_colvin_project:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvin_project:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvinproject:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvinproject:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-watchgod:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-watchgod:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_watchgod:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_watchgod:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvin_project:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvin:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvin:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvinproject:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:s_project:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:s_project:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python-watchgod:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python_watchgod:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:sproject:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:sproject:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:watchgod:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:watchgod:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:samuel_colvin:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:s_project:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:s:python-watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:s:python_watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:sproject:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:watchgod:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:python:watchgod:0.8.2:*:*:*:*:*:*:*', 'cpe:2.3:a:s:watchgod:0.8.2:*:*:*:*:*:*:*']",Samuel Colvin ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +wcwidth,0.2.12,MIT,PYTHON,"['cpe:2.3:a:jeff_quast_project:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quast_project:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quastproject:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quastproject:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python-wcwidth:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python-wcwidth:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python_wcwidth:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python_wcwidth:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quast_project:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quast:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quast:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quastproject:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contact_project:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contactproject:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python-wcwidth:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python_wcwidth:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:wcwidth:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:wcwidth:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:jeff_quast:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:contact:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:wcwidth:wcwidth:0.2.12:*:*:*:*:*:*:*', 'cpe:2.3:a:python:wcwidth:0.2.12:*:*:*:*:*:*:*']",Jeff Quast ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +websocket-client,1.7.0,Apache-2.0,PYTHON,"['cpe:2.3:a:python-websocket-client:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket-client:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket_client:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket_client:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp_project:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp_project:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket-client:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket-client:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket_client:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket_client:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket-client:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket-client:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket_client:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket_client:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_ppproject:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_ppproject:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_project:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_project:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lirisproject:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lirisproject:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp_project:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp_project:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-websocket:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_websocket:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket-client:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket-client:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket_client:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket_client:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris-pp:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris-pp:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_ppproject:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_ppproject:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_project:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_project:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris:python-websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris:python_websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lirisproject:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:lirisproject:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:websocket:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris-pp:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris-pp:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris_pp:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:websocket_client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris:websocket-client:1.7.0:*:*:*:*:*:*:*', 'cpe:2.3:a:liris:websocket_client:1.7.0:*:*:*:*:*:*:*']",liris ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +stringcase,1.2.0,MIT,PYTHON,"['cpe:2.3:a:okunishitaka_com_project:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_com_project:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_comproject:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_comproject:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishi_project:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishi_project:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishiproject:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishiproject:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_com_project:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-stringcase:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-stringcase:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_stringcase:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_stringcase:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka-com:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka-com:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_com:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_com:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_comproject:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishi_project:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishi:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishi:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishiproject:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-stringcase:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_stringcase:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stringcase:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stringcase:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka-com:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:okunishitaka_com:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:taka_okunishi:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:stringcase:stringcase:1.2.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:stringcase:1.2.0:*:*:*:*:*:*:*']",Taka Okunishi ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libnss3,2:3.68.2-0ubuntu1.2,BSD-3 MIT MPL-2.0 Zlib public-domain,dpkg,['cpe:2.3:a:libnss3:libnss3:2\\:3.68.2-0ubuntu1.2:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +gpg,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:gpg:gpg:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libc-bin,2.35-0ubuntu3.5,GFDL-1.3 GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libc-bin:libc-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc-bin:libc_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc_bin:libc-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc_bin:libc_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc:libc-bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc:libc_bin:2.35-0ubuntu3.5:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libc6-dev,2.35-0ubuntu3.5,GFDL-1.3 GPL-2 LGPL-2.1,dpkg,"['cpe:2.3:a:libc6-dev:libc6-dev:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc6-dev:libc6_dev:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc6_dev:libc6-dev:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc6_dev:libc6_dev:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc6:libc6-dev:2.35-0ubuntu3.5:*:*:*:*:*:*:*', 'cpe:2.3:a:libc6:libc6_dev:2.35-0ubuntu3.5:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +prompt-toolkit,3.0.41,Unknown,PYTHON,"['cpe:2.3:a:jonathan_slenders_project:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders_project:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slendersproject:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slendersproject:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt-toolkit:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt-toolkit:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt_toolkit:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt_toolkit:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders_project:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders_project:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slendersproject:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slendersproject:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt-toolkit:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt-toolkit:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt_toolkit:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt_toolkit:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt-toolkit:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt-toolkit:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt_toolkit:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt_toolkit:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:jonathan_slenders:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt-toolkit:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt-toolkit:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt_toolkit:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt_toolkit:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python-prompt:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python_prompt:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:prompt:prompt_toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python:prompt-toolkit:3.0.41:*:*:*:*:*:*:*', 'cpe:2.3:a:python:prompt_toolkit:3.0.41:*:*:*:*:*:*:*']",Jonathan Slenders,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libctf-nobfd0,2.38-4ubuntu2.3,GFDL GPL LGPL,dpkg,"['cpe:2.3:a:libctf-nobfd0:libctf-nobfd0:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libctf-nobfd0:libctf_nobfd0:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libctf_nobfd0:libctf-nobfd0:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libctf_nobfd0:libctf_nobfd0:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libctf:libctf-nobfd0:2.38-4ubuntu2.3:*:*:*:*:*:*:*', 'cpe:2.3:a:libctf:libctf_nobfd0:2.38-4ubuntu2.3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libctf0,2.38-4ubuntu2.3,GFDL GPL LGPL,dpkg,['cpe:2.3:a:libctf0:libctf0:2.38-4ubuntu2.3:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libcap-ng0,0.7.9-2.2build3,GPL-2 GPL-3 LGPL-2.1,dpkg,"['cpe:2.3:a:libcap-ng0:libcap-ng0:0.7.9-2.2build3:*:*:*:*:*:*:*', 'cpe:2.3:a:libcap-ng0:libcap_ng0:0.7.9-2.2build3:*:*:*:*:*:*:*', 'cpe:2.3:a:libcap_ng0:libcap-ng0:0.7.9-2.2build3:*:*:*:*:*:*:*', 'cpe:2.3:a:libcap_ng0:libcap_ng0:0.7.9-2.2build3:*:*:*:*:*:*:*', 'cpe:2.3:a:libcap:libcap-ng0:0.7.9-2.2build3:*:*:*:*:*:*:*', 'cpe:2.3:a:libcap:libcap_ng0:0.7.9-2.2build3:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +libdebconfclient0,0.261ubuntu1,Unknown,dpkg,['cpe:2.3:a:libdebconfclient0:libdebconfclient0:0.261ubuntu1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +colorama,0.4.6,Unknown,PYTHON,"['cpe:2.3:a:jonathan_hartley_\\>,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +boa,0.16.0,BSD 3-clause,PYTHON,"['cpe:2.3:a:wolf_vollprecht_project:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht_project:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprechtproject:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprechtproject:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht_project:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf-vollprecht:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf-vollprecht:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprechtproject:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-boa:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-boa:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_boa:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_boa:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf-vollprecht:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:wolf_vollprecht:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:boa:python-boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:boa:python_boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python-boa:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python_boa:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:python:boa:0.16.0:*:*:*:*:*:*:*', 'cpe:2.3:a:boa:boa:0.16.0:*:*:*:*:*:*:*']",Wolf Vollprecht ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +PySocks,1.7.1,BSD,PYTHON,"['cpe:2.3:a:anorov_vorona_project:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona_project:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_voronaproject:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_voronaproject:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_project:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_project:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona_project:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PySocks:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PySocks:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PySocks:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PySocks:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov-vorona:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov-vorona:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_voronaproject:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorovproject:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorovproject:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PySocks:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PySocks:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_project:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PySocks:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PySocks:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov-vorona:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorovproject:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PySocks:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:PySocks:1.7.1:*:*:*:*:*:*:*']",Anorov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dash,0.5.11+git20210903+057cd650a4ed-3build1,BSD-3-Clause BSD-3-clause Expat FSFUL FSFULLR GPL-2 GPL-2+ public-domain,dpkg,['cpe:2.3:a:dash:dash:0.5.11\\+git20210903\\+057cd650a4ed-3build1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +PySocks,1.7.1,BSD,PYTHON,"['cpe:2.3:a:anorov_vorona_project:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona_project:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_voronaproject:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_voronaproject:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_project:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_project:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona_project:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PySocks:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PySocks:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PySocks:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PySocks:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov-vorona:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov-vorona:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_voronaproject:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorovproject:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorovproject:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PySocks:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PySocks:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_project:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-PySocks:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_PySocks:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov-vorona:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov_vorona:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorovproject:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:PySocks:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:anorov:PySocks:1.7.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:PySocks:1.7.1:*:*:*:*:*:*:*']",Anorov ,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +dirmngr,2.2.27-3ubuntu2.1,BSD-3-clause CC0-1.0 Expat GPL-3 GPL-3+ LGPL-2.1 LGPL-2.1+ LGPL-3 LGPL-3+ RFC-Reference TinySCHEME permissive,dpkg,['cpe:2.3:a:dirmngr:dirmngr:2.2.27-3ubuntu2.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +fsspec,2023.12.1,BSD,PYTHON,"['cpe:2.3:a:python-fsspec:python-fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fsspec:python_fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fsspec:python-fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fsspec:python_fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:fsspec:python-fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:fsspec:python_fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python-fsspec:fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python-fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:python_fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python_fsspec:fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:fsspec:fsspec:2023.12.1:*:*:*:*:*:*:*', 'cpe:2.3:a:python:fsspec:2023.12.1:*:*:*:*:*:*:*']",Unknown,nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +e2fsprogs,1.46.5-2ubuntu1.1,GPL-2 LGPL-2,dpkg,['cpe:2.3:a:e2fsprogs:e2fsprogs:1.46.5-2ubuntu1.1:*:*:*:*:*:*:*'],Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 +fonts-dejavu-core,2.37-2build1,GPL-2 GPL-2+ bitstream-vera,dpkg,"['cpe:2.3:a:fonts-dejavu-core:fonts-dejavu-core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts-dejavu-core:fonts_dejavu_core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts_dejavu_core:fonts-dejavu-core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts_dejavu_core:fonts_dejavu_core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts-dejavu:fonts-dejavu-core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts-dejavu:fonts_dejavu_core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts_dejavu:fonts-dejavu-core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts_dejavu:fonts_dejavu_core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts:fonts-dejavu-core:2.37-2build1:*:*:*:*:*:*:*', 'cpe:2.3:a:fonts:fonts_dejavu_core:2.37-2build1:*:*:*:*:*:*:*']",Ubuntu Developers (maintainer),nvcr.io/nvidia/morpheus/morpheus:23.11-runtime,linux/amd64,02/01/2024 diff --git a/experimental/event-driven-rag-cve-analysis/default.env b/experimental/event-driven-rag-cve-analysis/default.env new file mode 100644 index 000000000..5d4b6deba --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/default.env @@ -0,0 +1,5 @@ +NGC_API_KEY=CYBER_DEV_DAY +NGC_ORG_ID=CYBER_DEV_DAY +NVIDIA_API_KEY=nvapi-CYBER_DEV_DAY +NGC_API_BASE="https://morpheus-sherlock.nvidia.com/nemo/v1" +NVIDIA_API_BASE="https://morpheus-sherlock.nvidia.com/nvcf/v2" diff --git a/experimental/event-driven-rag-cve-analysis/docker-compose.yml b/experimental/event-driven-rag-cve-analysis/docker-compose.yml new file mode 100755 index 000000000..1376d2601 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/docker-compose.yml @@ -0,0 +1,89 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +version: '3.3' + +name: cyber-dev-day + +services: + + cyber-dev-day: + build: + context: . + dockerfile: ./Dockerfile + args: + - MORPHEUS_CONTAINER=${MORPHEUS_CONTAINER:-nvcr.io/nvidia/morpheus/morpheus} + - MORPHEUS_CONTAINER_VERSION=${MORPHEUS_CONTAINER_VERSION:-v24.03.02-runtime} + target: jupyter + image: morpheus-cyber-dev-day-2 + entrypoint: /workspace/entrypoint.sh + ports: + - "26302" + - "${JUPYTER_PORT:-8888}:${JUPYTER_PORT:-8888}" + working_dir: /workspace + command: jupyter-lab --no-browser --allow-root --ip='*' --port=${JUPYTER_PORT:-8888} + deploy: + resources: + reservations: + devices: + - driver: nvidia + capabilities: [ gpu ] + networks: + - proxy + # Uncomment if the .env file issue is resolved: https://github.com/docker/compose/issues/9181#issuecomment-1996016211 + # env_file: + # - path: .env + # required: "false" + environment: + - TERM=${TERM:-} + # Workaround until this is working: https://github.com/docker/compose/issues/9181#issuecomment-1996016211 + - OPENAI_API_KEY= + # Overwrite any environment variables in the .env file with URLs needed in the network + - OPENAI_API_BASE=https://integrate.api.nvidia.com/v1 + - OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1 + volumes: + - .:/workspace + - build-cache:/workspace/.cache + - build-dir:/workspace/build-docker + cap_add: + - sys_nice + restart: always + + proxy-cache: + image: nginx:1.23.4 + ports: + - "81" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/template-variables.conf:/etc/nginx/templates/10-variables.conf.template:ro + - proxy-cache:/server_cache:rw + environment: + # Workaround until this is working: https://github.com/docker/compose/issues/9181#issuecomment-1996016211 + - NGC_API_KEY=${NGC_API_KEY:-CYBER_DEV_DAY} + - NGC_ORG_ID=${NGC_ORG_ID:-CYBER_DEV_DAY} + - NVIDIA_API_KEY=${NVIDIA_API_KEY:-nvapi-CYBER_DEV_DAY} + networks: + - proxy + +networks: + proxy: + driver: bridge + +volumes: + proxy-cache: + driver: local + build-cache: + driver: local + build-dir: + driver: local diff --git a/experimental/event-driven-rag-cve-analysis/entrypoint.sh b/experimental/event-driven-rag-cve-analysis/entrypoint.sh new file mode 100755 index 000000000..5c307ceb3 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Activate "morpheus" conda environment +. /opt/conda/etc/profile.d/conda.sh +conda activate morpheus + +# Run whatever user wants +exec "$@" diff --git a/experimental/event-driven-rag-cve-analysis/nginx/.gitignore b/experimental/event-driven-rag-cve-analysis/nginx/.gitignore new file mode 100644 index 000000000..2cbdd5c3a --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/nginx/.gitignore @@ -0,0 +1,3 @@ + +# Ignore any secret certificate files +*.pem diff --git a/experimental/event-driven-rag-cve-analysis/nginx/nginx.conf b/experimental/event-driven-rag-cve-analysis/nginx/nginx.conf new file mode 100644 index 000000000..1f1aeb0af --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/nginx/nginx.conf @@ -0,0 +1,204 @@ +events { + worker_connections 1024; +} + +http { + proxy_ssl_server_name on; + + proxy_cache_path /server_cache levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=14d use_temp_path=off; + + error_log /dev/stdout info; + + log_format upstream_time '$remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent"' + 'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"'; + + log_format cache_log '$remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + 'Cache: $upstream_cache_status'; + + log_format no_cache_log '[NOCACHE] $remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + 'Cache: $upstream_cache_status'; + + include /etc/nginx/conf.d/10-variables.conf; + + # upstream loadbalancer { + + # # enable sticky session based on IP + # ip_hash; + # keepalive 1024; + + # server cve-tool:26302; + # } + + server { + listen 81; + # listen 443 ssl; + # listen [::]:443 ssl; + # server_name localhost; + # ssl_certificate /etc/nginx/ssl/cert.pem; + # ssl_certificate_key /etc/nginx/ssl/key.pem; + + proxy_http_version 1.1; + proxy_set_header Host $host; + + proxy_busy_buffers_size 512k; + proxy_buffers 4 512k; + proxy_buffer_size 256k; + + # rewrite_log on; + + # location / { + # proxy_pass "http://loadbalancer"; + # proxy_http_version 1.1; + # proxy_set_header Upgrade $http_upgrade; + # proxy_set_header Connection "upgrade"; + # proxy_set_header Host $host; + # } + + location /openai { + proxy_set_header Host api.openai.com; + + location ~* ^\/openai\/v1\/((engines\/.+\/)?(?:chat\/completions|completions|edits|moderations|answers|embeddings))$ { + rewrite ^\/openai(\/.*)$ $1 break; + proxy_pass https://api.openai.com; + proxy_set_header Connection ''; + proxy_cache my_cache; + proxy_cache_methods POST; + proxy_cache_key "$request_method|$request_uri|$request_body"; + proxy_cache_valid 200 14d; + proxy_cache_valid 404 1m; + proxy_read_timeout 8m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + proxy_cache_lock on; + access_log /dev/stdout cache_log; + proxy_ignore_headers Cache-Control; + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + add_header X-Cache-Status $upstream_cache_status; + client_body_buffer_size 4m; + } + + location /openai/v1 { + rewrite ^\/openai(\/.*)$ $1 break; + proxy_pass https://api.openai.com; + access_log /dev/stdout no_cache_log; + } + } + + location /nemo { + proxy_set_header Host api.llm.ngc.nvidia.com; + + location ~* ^\/nemo\/v1\/models(\/.+\/completions)?$ { + rewrite ^\/nemo(\/.*)$ $1 break; + proxy_pass https://api.llm.ngc.nvidia.com; + proxy_set_header Connection ''; + proxy_set_header Authorization $nemo_http_authorization; + proxy_set_header Organization-ID $nemo_http_organization_id; + proxy_cache my_cache; + proxy_cache_methods GET POST; + proxy_cache_key "$request_method|$request_uri|$request_body"; + proxy_cache_valid 200 14d; + proxy_cache_valid 404 1m; + proxy_read_timeout 8m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + proxy_cache_lock on; + access_log /dev/stdout cache_log; + proxy_ignore_headers Cache-Control; + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + add_header X-Cache-Status $upstream_cache_status; + client_body_buffer_size 4m; + } + + location /nemo/v1 { + rewrite ^\/nemo(\/.*)$ $1 break; + proxy_pass https://api.llm.ngc.nvidia.com; + access_log /dev/stdout no_cache_log; + } + } + + location /nvcf { + proxy_set_header Host api.nvcf.nvidia.com; + + location ~* ^\/nvcf\/v2\/nvcf\/(pexec\/functions\/.+)$ { + rewrite ^\/nvcf(\/.*)$ $1 break; + proxy_pass https://api.nvcf.nvidia.com; + proxy_set_header Connection ''; + proxy_set_header Authorization $nvcf_http_authorization; + proxy_cache my_cache; + proxy_cache_methods POST; + proxy_cache_key "$request_method|$request_uri|$request_body"; + proxy_cache_valid 200 14d; + proxy_cache_valid 202 14d; + proxy_cache_valid 404 1m; + proxy_read_timeout 8m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + proxy_cache_lock on; + access_log /dev/stdout cache_log; + proxy_ignore_headers Cache-Control; + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + add_header X-Cache-Status $upstream_cache_status always; + client_body_buffer_size 4m; + } + + location ~* ^\/nvcf\/v2\/nvcf\/(pexec\/status\/.+)$ { + rewrite ^\/nvcf(\/.*)$ $1 break; + proxy_pass https://api.nvcf.nvidia.com; + proxy_set_header Connection ''; + proxy_set_header Authorization $nvcf_http_authorization; + proxy_cache my_cache; + proxy_cache_methods GET; + proxy_cache_key "$request_method|$request_uri"; + proxy_cache_valid 200 14d; + proxy_cache_valid 404 1m; + proxy_read_timeout 8m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + proxy_cache_lock on; + access_log /dev/stdout cache_log; + proxy_ignore_headers Cache-Control; + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + add_header X-Cache-Status $upstream_cache_status always; + client_body_buffer_size 4m; + } + + location /nvcf/v2 { + rewrite ^\/nvcf(\/.*)$ $1 break; + proxy_pass https://api.nvcf.nvidia.com; + access_log /dev/stdout no_cache_log; + } + } + + location /serpapi/ { + proxy_set_header Host serpapi.com; + + proxy_pass https://serpapi.com/; + proxy_set_header Connection ''; + proxy_cache my_cache; + proxy_cache_methods GET; + proxy_cache_key "$request_method|$request_uri"; + proxy_cache_valid 200 14d; + proxy_cache_valid 404 1m; + proxy_read_timeout 8m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + proxy_cache_lock on; + access_log /dev/stdout cache_log; + proxy_ignore_headers Cache-Control; + proxy_ignore_headers "Set-Cookie"; + proxy_hide_header "Set-Cookie"; + add_header X-Cache-Status $upstream_cache_status; + client_body_buffer_size 4m; + } + } +} diff --git a/experimental/event-driven-rag-cve-analysis/nginx/template-variables.conf b/experimental/event-driven-rag-cve-analysis/nginx/template-variables.conf new file mode 100644 index 000000000..071012c26 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/nginx/template-variables.conf @@ -0,0 +1,15 @@ +map $http_authorization $nemo_http_authorization { + default $http_authorization; + "Bearer CYBER_DEV_DAY" "Bearer ${NGC_API_KEY}"; +} + +map $http_organization_id $nemo_http_organization_id { + default $http_organization_id; + "CYBER_DEV_DAY" "${NGC_ORG_ID}"; +} + +map $http_authorization $nvcf_http_authorization { + default $http_authorization; + "Bearer CYBER_DEV_DAY" "Bearer ${NVIDIA_API_KEY}"; + "Bearer nvapi-CYBER_DEV_DAY" "Bearer ${NVIDIA_API_KEY}"; +} diff --git a/experimental/event-driven-rag-cve-analysis/notebooks/cyber-dev-day.ipynb b/experimental/event-driven-rag-cve-analysis/notebooks/cyber-dev-day.ipynb new file mode 100644 index 000000000..123f2d051 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/notebooks/cyber-dev-day.ipynb @@ -0,0 +1,2229 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2941e94f-db20-44a5-ab87-2cab499825f7", + "metadata": { + "tags": [] + }, + "source": [ + "# An Introduction to Developing Agents with NVIDIA Morpheus\n", + "\n", + "## Introduction\n", + "\n", + "**Generative AI (GenAI)** and **Large Language Models (LLMs)** are becoming essential tools in **cybersecurity** in part due to their ability to enhance the efficiency of cyber threat detection and response by **accelerating analyst workflows**. However, prototyping and moving these accelerated workflows into production can be daunting.\n", + "\n", + "Cybersecurity remains among the top three challenges impacting every industry—from the public sector to financial services, telecommunications, retail, automotive, and more. Most CEOs believe organizations with the most **advanced generative AI capabilities** will have a competitive advantage and are looking for ways to incorporate this into their business. While adversaries are already leveraging generative AI in their attacks, there is significant potential to harness this power for **cyber defense**.\n", + "\n", + "This hands-on tutorial will focus on **accelerating an exploitability analysis workflow** to increase analyst productivity and enhance cybersecurity defenses.\n", + "\n", + "### Problem Statement: Common Vulnerabilities and Exposures (CVE) Impact Analysis\n", + "\n", + "Determining the impact of a documented **CVE** on a specific project or container is a labor-intensive and manual task. This intricate process involves the collection, comprehension, and synthesis of various pieces of information to ascertain whether immediate remediation, such as patching, is necessary upon the identification of a new CVE.\n", + "\n", + "#### Challenges\n", + "\n", + "- **Information Collection:** The process involves significant manual labor to collect and synthesize relevant information.\n", + "- **Decision Complexity:** Decisions on whether to update a library impacted by a CVE often hinge on various considerations, including:\n", + " - **Scan False Positives:** Occasionally, vulnerability scans may incorrectly flag a library as vulnerable, leading to a false alarm.\n", + " - **Mitigating Factors:** In some cases, existing safeguards within the environment may reduce or negate the risk posed by a CVE.\n", + " - **Lack of Required Environments or Dependencies:** For an exploit to succeed, specific conditions must be met. The absence of these necessary elements can render a vulnerability irrelevant.\n", + "- **Manual Documentation:** Once an analyst has determined the library is not affected, a **Vulnerability Exploitability eXchange (VEX)** document must be created to standardize and distribute the results.\n", + "\n", + "The efficiency of this process can be significantly enhanced through the deployment of an **event-driven LLM agent pipeline**.\n", + "\n", + "### Tutorial Goals\n", + "\n", + "Our team developed a **cybersecurity vulnerability analysis tool** to aid in assessing the exploitability of CVEs in specific projects and containers. This tutorial will guide you step-by-step through the process of using **LLMs, Retrieval-Augmented Generation (RAG), and agents** to create both a toy version and a microservice running **LLM-powered CVE exploitability analysis**.\n", + "\n", + "You'll have the chance to experiment with various modules, boosting your skills and understanding of these technologies. This experience will prepare you to later expand your use case by exploring new functionalities, enhancing the current setup, or even creating your own tailored solutions to meet specific needs or address new challenges.\n", + "\n", + "## Table of Contents\n", + "\n", + "- [0 - Environment Setup](#0---Environment-Setup)\n", + "- [1 - Intro to Interacting with LLMs](#1---Intro-to-Interacting-with-LLMs)\n", + " - [1.1 - Python Calls to LLM API](#1.1---Python-Calls-to-LLM-API)\n", + " - [1.2 - Prompt Engineering](#1.2---Prompt-Engineering)\n", + " - [1.3 - Prompt Templating](#1.3---Prompt-Templating)\n", + " - [1.4 - One-Shot Learning](#1.4---One-Shot-Learning)\n", + " - [1.5 - Few-Shot Learning](#1.5---Few-Shot-Learning)\n", + " - [1.6 - Evaluation Strategies](#1.6---Evaluation-Strategies)\n", + "- [2 - Prototyping](#2---Prototyping)\n", + " - [2.1 - Overview](#21---overview)\n", + " - [2.2 - Building the Vector Database](#22---building-the-vector-database)\n", + " - [2.3 - Running a RAG pipeline with Morpheus](#23---running-a-rag-pipeline-with-morpheus)\n", + " - [2.4 - Running the CVE Pipeline with Morpheus](#24---running-the-cve-pipeline-with-morpheus)\n", + "- [3 - Beyond Prototyping](#3---Beyond-Prototyping)\n", + " - [3.1 - Improving the Model](#31---improving-the-model)\n", + " - [3.2 - Scaling the Pipeline](#32---scaling-the-pipeline)\n", + " - [3.3 - Event Driven Pipeline: Creating a Microservice](#33---event-driven-pipeline-creating-a-microservice) \n", + "- [4 - Conclusion](#4---conclusion)\n", + "\n", + "
\n", + "Note: Please continue running the notebook up to Part 1 during the introduction presentation to ensure your environment is set up correctly.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "1392801d-3325-4297-974a-e430f5248170", + "metadata": {}, + "source": [ + "---\n" + ] + }, + { + "cell_type": "markdown", + "id": "ff405752-d264-49b4-946f-ccb693ccb732", + "metadata": {}, + "source": [ + "## 0 - Environment Setup\n" + ] + }, + { + "cell_type": "markdown", + "id": "4700a3a1", + "metadata": {}, + "source": [ + "The following code blocks are used to setup environment variables and imports for the rest of the notebook.\n" + ] + }, + { + "cell_type": "code", + "id": "a60d2a30", + "metadata": { + "tags": [] + }, + "source": [ + "%load_ext autoreload\n", + "%aimport -logging\n", + "%autoreload 2\n", + "\n", + "# Ensure that the morpheus directory is in the python path. This may not need to be run depending on the environment setup\n", + "import sys\n", + "import os\n", + "import warnings\n", + "\n", + "warnings.simplefilter(action='ignore', category=FutureWarning)\n", + "\n", + "if (\"MORPHEUS_ROOT\" not in os.environ):\n", + " os.environ[\"MORPHEUS_ROOT\"] = os.path.abspath(\"../\")\n", + "\n", + "llm_dir = os.path.abspath(os.path.join(os.getenv(\"MORPHEUS_ROOT\", \"../\")))\n", + "\n", + "if (llm_dir not in sys.path):\n", + " sys.path.append(llm_dir)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "3523bc32", + "metadata": {}, + "source": [ + "Ensure the necessary environment variables are set. As a last resort, try to load them from a `.env` file.\n" + ] + }, + { + "cell_type": "code", + "id": "ef295094", + "metadata": { + "tags": [] + }, + "source": [ + "# Ensure that the current environment is set up with API keys\n", + "required_env_vars = [\"MORPHEUS_ROOT\", \"OPENAI_API_KEY\", \"OPENAI_BASE_URL\"]\n", + "\n", + "if (not all([var in os.environ for var in required_env_vars])):\n", + "\n", + " # Try loading an .env file if it exists\n", + " from dotenv import load_dotenv\n", + "\n", + " load_dotenv()\n", + "\n", + " # Check again\n", + " if (not all([var in os.environ for var in required_env_vars])):\n", + " raise ValueError(f\"Please set the following environment variables: {required_env_vars}\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "86203ec2", + "metadata": {}, + "source": [ + "Import some common libraries to allow them to be used later in the notebook.\n" + ] + }, + { + "cell_type": "code", + "id": "e2aa2691", + "metadata": { + "tags": [] + }, + "source": [ + "import logging\n", + "import os\n", + "import time\n", + "\n", + "import pandas as pd\n", + "from openai import OpenAI\n", + "\n", + "import cudf\n", + "\n", + "# Finally, ensure Morpheus is installed correctly\n", + "import morpheus._lib" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "7932f728", + "metadata": {}, + "source": [ + "Configure logging to allow Morpheus messages to appear in the notebook.\n" + ] + }, + { + "cell_type": "code", + "id": "a9ab76ad", + "metadata": { + "tags": [] + }, + "source": [ + "# Configure logging\n", + "import cyber_dev_day\n", + "\n", + "# Create a logger for this module. Use the cyber_dev_day module name because the notebook will just be __main__\n", + "logger = logging.getLogger(cyber_dev_day.__name__)\n", + "\n", + "# Configure the parent logger log level\n", + "logger.parent.setLevel(logging.INFO)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "1cfc3ce8", + "metadata": {}, + "source": [ + "Finally, test out the logger to ensure that it is working correctly. You should see a message printed to the console.\n" + ] + }, + { + "cell_type": "code", + "id": "78a1fcfd", + "metadata": { + "tags": [] + }, + "source": [ + "logger.info(\"Successfully configured logging!\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "b911e7b9-18bd-4972-a7e1-ff1c976ba66b", + "metadata": {}, + "source": [ + "---\n", + "\n", + "
\n", + "Note: Please wait here until instructed to continue with running Part 1 of the notebook.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "5bb62b83", + "metadata": {}, + "source": [ + "## 1 - Intro to Interacting with LLMs\n", + "\n", + "This section will go over how to integrate LLMs into code with Python based examples. We will highlight some of the basic techniques for using and improving calls to LLMs for cybersecurity use cases.\n", + "\n", + "- [1.1 - Python Calls to LLM API](#1.1---Python-Calls-to-LLM-API)\n", + "- [1.2 - Prompt Engineering](#1.2---Prompt-Engineering)\n", + "- [1.3 - Prompt Templating](#1.3---Prompt-Templating)\n", + "- [1.4 - One-Shot Learning](#1.4---One-Shot-Learning)\n", + "- [1.5 - Few-Shot Learning](#1.5---Few-Shot-Learning)\n", + "- [1.6 - Evaluation Strategies](#1.6---Evaluation-Strategies)\n", + "\n", + "In this lab, we will be using [NVIDIA Inference Microservices (NIM)](https://www.nvidia.com/en-us/ai-data-science/generative-ai/nemo-framework/) (previously named NeMo) as our generative AI platform. NIM is a cloud-native framework for building, customizing and deploying generative AI models with a familiar ChatGPT-like interface. Utilizing NIM (or any other generative AI service) in our pipelines allows us to offload the heavy lifting of language model inference to a dedicated service, freeing up our own resources for other tasks. All requests to the NIM service are made via an HTTP API, which allows us to easily integrate it into our existing codebase.\n", + "\n", + "To simplify the process of interacting with the LLM, we will use a Python client library ([`openai`](https://pypi.org/project/openai/0.26.5/)) that wraps the HTTP API. This library provides a simple interface for making requests to the LLM, and handles the details of making HTTP requests and parsing the responses. This allows us to focus on the high-level logic of our application, rather than the low-level details of making HTTP requests.\n", + "\n", + "Before sending requests to the LLM, we need to set up a connection object, `llm_client` which is shown below. We will use the `completions` endpoint of the connection object to send requests to the LLM for the remainder of this section.\n", + "\n", + "It's important to note here that although we store the NGC API Key under the OPENAI_API_KEY variable, we will be interacting with NVIDIA hosted LLMs and not OpenAI LLMs.\n", + "\n", + "NVIDIA NIMs are OpenAI API compliant to maximize usability, so we will be using the openai with package as a wrapped to make API calls.\n" + ] + }, + { + "cell_type": "code", + "id": "67c8c1d6", + "metadata": { + "tags": [] + }, + "source": [ + "# Create the connection object. The API key and organization ID are read from the environment variables NGC_API_KEY and\n", + "# NGC_ORG_ID respectively\n", + "api_key = os.getenv(\"OPENAI_API_KEY\")\n", + "base_url = os.getenv(\"OPENAI_BASE_URL\")\n", + "\n", + "llm_client = OpenAI(\n", + " base_url = base_url,\n", + " api_key = api_key\n", + ")\n", + "\n", + "\n", + "print(f\"Connected to LLM hosted at: {base_url}\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "4639ba36-02ac-4a94-9815-182bbda12c38", + "metadata": {}, + "source": [ + "### 1.1 - Python Calls to LLM API\n", + "\n", + "This section demonstrates executing a call to the LLM API for cybersecurity knowledge support. This could stand alone as a potential use case where we have a cyber knowledge assistant to aid junior cyber analysts.\n", + "\n", + "
Query
\n", + "
How can one determine if a CVE is vulnerable in a specific environment?
\n", + "\n", + "\n", + "The code snippet below utilizes the `chat.completions.create()` method of the connection object (`llm_client`) to query the LLM, detailing the potential **model parameters** that can be provided:\n", + "\n", + "- **Temperature**: Controls the creativity of the model. Higher values enable the model to generate more creative outputs.\n", + "- **Top P**: Controls the creativity of the model. Higher values enable the model to generate more creative outputs, suitable for tasks such as creative writing. This determines the minimum number of highest-probability tokens whose probabilities sum to or exceed the Top P value, from which the next token will be selected at random during text generation.\n", + "- **Seed**: Affects the generation of random results by the model. It is possible to reproduce results by fixing the random seed (assuming all other hyperparameters are also fixed).\n", + "- **Presence Penalty**: Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.\n", + "- **Frequency Penalty**: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.\n", + "- **Stream**:If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.\n" + ] + }, + { + "cell_type": "code", + "id": "739e8a57-d198-4f6b-911b-0500f97a983d", + "metadata": { + "tags": [] + }, + "source": [ + "completion = llm_client.chat.completions.create(\n", + " model=\"mistralai/mixtral-8x22b-instruct-v0.1\",\n", + " messages=[{\"role\":\"user\",\"content\":\"How can one determine if a CVE is vulnerable in a specific environment?\"}], #Prompt goes here\n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=True\n", + " \n", + ")\n", + "\n", + "for chunk in completion:\n", + " if chunk.choices[0].delta.content is not None:\n", + " print(chunk.choices[0].delta.content, end=\"\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "a21d4222-9f6d-46cf-b037-b765889825cc", + "metadata": { + "tags": [] + }, + "source": [ + "#### 1.1.1 - Explore On Your Own: Different Models\n", + "\n", + "Try another model such as from https://build.nvidia.com/explore/reasoning below\n" + ] + }, + { + "cell_type": "code", + "id": "70ef49a4-df05-4f68-8cd8-7eb053e31397", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try different models\n", + "# completion = llm_client.chat.completions.create(\n", + "# model=\"\",\n", + "# messages=[{\"role\":\"user\",\"content\":\"How can one determine if a CVE is vulnerable in a specific environment?\"}], #Prompt goes here\n", + "# temperature=0.5,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=True\n", + " \n", + "# )\n", + "\n", + "# for chunk in completion:\n", + "# if chunk.choices[0].delta.content is not None:\n", + "# print(chunk.choices[0].delta.content, end=\"\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "6ffff783-1e41-46cb-a819-e9fb96252d31", + "metadata": {}, + "source": [ + "#### 1.1.2 - Explore On Your Own: Model Parameters\n", + "\n", + "- How do the different models compare? Can you change the parameters (like `temperature` or `presence_penalty`) to help the smaller models improve?\n", + "\n", + "- What are some other cybersecurity questions you could ask an LLM to upskill a junior analyst?" + ] + }, + { + "cell_type": "markdown", + "id": "1ec13bd8-e835-4260-8b09-f419513610e3", + "metadata": { + "tags": [] + }, + "source": [ + "Try a few `temperature` values such as `[0.0, 0.5, 0.7, 0.9]`.\n", + "\n", + "What happens to the model's output with higher creativity?" + ] + }, + { + "cell_type": "code", + "id": "fec55c66-1b44-44a2-a69d-c899c08f4ccf", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try different parameters\n", + "# # Analyze output of the model for different value of temperature and top_k\n", + "# for temp in [0.0, 0.5, 0.7, 0.9]:\n", + "# completion = llm_client.chat.completions.create(\n", + "# model=\"mistralai/mixtral-8x22b-instruct-v0.1\",\n", + "# messages=[{\"role\":\"user\",\"content\":\"How can one determine if a CVE is vulnerable in a specific environment?\"}], #Prompt goes here\n", + "# temperature=temp,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=True\n", + "\n", + "# )\n", + "\n", + "# for chunk in completion:\n", + "# if chunk.choices[0].delta.content is not None:\n", + "# print(chunk.choices[0].delta.content, end=\"\")\n", + " \n", + "# print(\"\\n-----\\n\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "a03af5d2-0931-4e0c-a27a-d280c9f77fcb", + "metadata": { + "tags": [] + }, + "source": [ + "---\n", + "\n", + "### 1.2 - Prompt Engineering\n", + "\n", + "Sometimes, a simple prompt might not deliver the results we're aiming for. That's where prompt engineering steps in.
\n", + "Prompt engineering is an iterative process that focuses on crafting prompts to clearly communicate our intentions to the model, guiding it to generate the most relevant and accurate responses. This approach helps optimize the model's performance, especially in specialized fields.
(Some tips for improving performance using prompt engineering can be found here https://www.promptingguide.ai/introduction/tips.)\n", + "\n", + "**Implementing Personas in Prompts**\n", + "\n", + "An interesting approach within prompt engineering involves assigning a **persona** to the model. By doing this, we can guide the model to produce responses that align with a specific character, making the interaction more tailored, in-depth, and relevant to our needs. The example below demonstrates a way to achieve persona prompting.\n", + "\n", + "
Persona
\n", + "
You are a highly experienced and knowledgeable cybersecurity expert with a deep understanding of cyber threats, network defense strategies, and the latest in cybersecurity technology. Your communication is clear, concise, and authoritative, aiming to educate and inform on best practices for digital security.
\n", + "
Query
\n", + "
How can one determine if a CVE is vulnerable in a specific environment?
\n", + "\n" + ] + }, + { + "cell_type": "code", + "id": "95010654-9f3e-4cb1-bb31-d4ceb288c9da", + "metadata": { + "tags": [] + }, + "source": [ + "security_expert_persona = (\n", + " \"You are a highly experienced and knowledgeable cybersecurity expert with a deep understanding of cyber threats, \"\n", + " \"network defense strategies, and the latest in cybersecurity technology. Your communication is clear, concise, and authoritative, \"\n", + " \"aiming to educate and inform on best practices for digital security.\")\n", + "formatted_prompt = \"{persona} {query}\".format(\n", + " persona=security_expert_persona, query=\"How can one determine if a CVE is vulnerable in a specific environment?\")\n", + "\n", + "completion = llm_client.chat.completions.create(\n", + " model=\"mistralai/mixtral-8x22b-instruct-v0.1\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}], \n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=True\n", + " \n", + ")\n", + "\n", + "for chunk in completion:\n", + " if chunk.choices[0].delta.content is not None:\n", + " print(chunk.choices[0].delta.content, end=\"\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "1035ba69-8a51-4d92-950f-d1b4e420cd70", + "metadata": { + "tags": [] + }, + "source": [ + "#### 1.2.1 - Explore on your own: Different Personas\n", + "\n", + "Does the persona improve performance? What happens if you change the persona or attributes such as communication style?\n" + ] + }, + { + "cell_type": "code", + "id": "f4f6ebc5-a1ff-4e27-8083-8f9757fcb6ee", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try a different persona\n", + "# # Here is an example:\n", + "# persona = \"You are an elementary school teacher who teaches digital security.\",\n", + "# formatted_prompt = \"{persona} {query}\".format(\n", + "# persona=persona, query=\"How can one determine if a CVE is vulnerable in a specific environment?\")\n", + "\n", + "# completion = llm_client.chat.completions.create(\n", + "# model=\"mistralai/mixtral-8x22b-instruct-v0.1\",\n", + "# messages=[{\"role\":\"user\",\"content\":formatted_prompt}], \n", + "# temperature=0.5,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=True\n", + " \n", + "# )\n", + "\n", + "# for chunk in completion:\n", + "# if chunk.choices[0].delta.content is not None:\n", + "# print(chunk.choices[0].delta.content, end=\"\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "b265febf-5117-4010-a879-dc41ab957c5d", + "metadata": { + "tags": [] + }, + "source": [ + "---\n", + "### 1.3 - Prompt Templating\n", + "\n", + "While cyber knowledge assistants are valuable, there are occasions when we need more **detailed information** or support on particular subjects, such as specific **malware** or a **security vulnerability** we're examining.
\n", + "For instance, if we're assessing whether a known vulnerability can be exploited in our systems, how can we leverage LLM to guide us through the process?\n", + "Can the LLM provide us with clear instructions on what steps to take?\n", + "\n", + "
\n", + "
Use Case
\n", + "
Utilizing LLMs to Evaluate System Vulnerabilities to Specific CVEs
\n", + "
Query
\n", + "
How can I determine if my specific environment is affected by CVE-2023-47248?
\n", + "
\n" + ] + }, + { + "cell_type": "code", + "id": "402c784d-6ae2-4468-b121-b820879aa36f", + "metadata": { + "tags": [] + }, + "source": [ + "formatted_prompt = \"{persona} {query}\".format(\n", + " persona=\"You are helpful cybersecurity expert with an IQ of 140.\",\n", + " query=\"How can I determine if my specific environment is affected by CVE-2023-47248?\")\n", + "\n", + "completion = llm_client.chat.completions.create(\n", + " model=\"mistralai/mixtral-8x22b-instruct-v0.1\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}], \n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=True\n", + " \n", + ")\n", + "\n", + "for chunk in completion:\n", + " if chunk.choices[0].delta.content is not None:\n", + " print(chunk.choices[0].delta.content, end=\"\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "d3bf4e69-e720-4d49-b203-0f4a38d97f13", + "metadata": { + "tags": [] + }, + "source": [ + "
\n", + "\n", + "**Observation**
\n", + "Although the LLM offered general cybersecurity guidance, it couldn't give specific details about the CVE due to the limited capability caused by its offline nature.\n", + "\n", + "**Potential Solution**
\n", + "To enhance the model's effectiveness, we can directly include specific details about the CVE in our prompts. This approach leverages the model's ability to analyze information and compensates for its inability to access real-time data.
\n", + "By doing so, the model can provide more precise and helpful recommendations concerning particular issues.\n", + "\n", + "**CVE Intel Examples**
\n", + "Here are two example CVEs that we'll be using as recurring examples throughout the notebook (the information is sourced from the internet): " + ] + }, + { + "cell_type": "code", + "id": "70451746", + "metadata": { + "tags": [] + }, + "source": [ + "PYARROW_CVE_INTEL = dict(\n", + " cve=\"CVE-2023-47248\",\n", + " cve_description=\n", + " \"Deserialization of untrusted data in IPC and Parquet readers in PyArrow before version 14.0.0 allows arbitrary code execution. It is recommended \\\n", + "that users of PyArrow upgrade to 14.0.1. Similarly, it is recommended that downstream libraries upgrade their dependency requirements to PyArrow 14.0.1 or later. PyPI \\\n", + "packages are already available, and we hope that conda-forge packages will be available soon. If it is not possible to upgrade, we provide a separate package `pyarrow-hotfix` \\\n", + "for you to import to your codebase. This fix disables the vulnerability on older PyArrow versions. See https://pypi.org/project/pyarrow-hotfix/ for importing instructions.\",\n", + " vuln_package=\"PyArrow\",\n", + " vuln_package_version=\"before 14.0.1\",\n", + " cvss3=\"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\",\n", + ")\n", + "\n", + "LOG4J_CVE_INTEL = dict(\n", + " cve=\"CVE-2021-44228\",\n", + " cve_description=\n", + " \"Apache Log4j2 2.0-beta9 through 2.15.0 (excluding security releases 2.12.2, 2.12.3, and 2.3.1) JNDI features used in \"\n", + " \"configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker \"\n", + " \"who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution \"\n", + " \"is enabled. From log4j 2.15.0, this behavior has been disabled by default. From version 2.16.0 (along with 2.12.2, 2.12.3, and 2.3.1), this \"\n", + " \"functionality has been completely removed. Note that this vulnerability is specific to log4j-core and does not affect log4net, log4cxx, or \"\n", + " \"other Apache Logging Services projects.\",\n", + " vuln_package=\"log4j\",\n", + " vuln_package_version=\n", + " \"from 2.0.1 up to (excluding) 2.3.1, from 2.4.0 up to (excluding) 2.12.2, from 2.13.0 up to (excluding) 2.15.0\",\n", + " cvss3=\"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H\",\n", + ")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "b3ad0c8e", + "metadata": {}, + "source": [ + "Below is an example illustrating how to create a prompt template that allows us to easily insert information of any given CVE:" + ] + }, + { + "cell_type": "code", + "id": "f799d938-0761-40f1-9007-05d900609bef", + "metadata": { + "tags": [] + }, + "source": [ + "prompt_template = \"\"\"Generate a checklist for a security analyst to use when assessing the exploitability of a specific CVE within a containerized environment. \\\n", + "For each checklist item, start with an action verb, making it clear and actionable. Provide the checklist as a Python list of strings. \\\n", + "Utilize the provided CVE details below to tailor the checklist items specifically for this CVE.\n", + "CVE Details:\n", + "- CVE ID: {cve}\n", + "- Description: {cve_description}\n", + "- Vulnerable Package Name: {vuln_package}\n", + "- Vulnerable Package Version: {vuln_package_version}\n", + "- CVSS3 Vector String: {cvss3}\"\"\"\n", + "\n", + "formatted_prompt = prompt_template.format(**PYARROW_CVE_INTEL)\n", + "\n", + "completion = llm_client.chat.completions.create(\n", + " model=\"mistralai/mixtral-8x22b-instruct-v0.1\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}],\n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=False\n", + " \n", + ")\n", + "\n", + "print(completion.choices[0].message.content)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "f374c4a4-67b1-4dad-92c8-ca74995af35c", + "metadata": {}, + "source": [ + "#### 1.3.1 - Reflective Questions\n", + "\n", + "
\n", + "
1. Assessing the Model's Output
\n", + "
⦁ Review the checklist provided by the model. Do the steps outlined seem practical and relevant to the CVE?
\n", + "
⦁ How does the generated checklist aligns with your expectations?

\n", + "
2. Checking for Format Compliance
\n", + "
⦁ Did the model generate the output in the format we requested, specifically as a Python list of strings?
\n", + "
⦁ Consider the importance of format in data pipelines and how it affects the usability of the model's output.

\n", + "
3. Measuring Accuracy
\n", + "
⦁ How can we determine the accuracy of a language model's output?
\n", + "
⦁ Think about the criteria you would use to evaluate whether the checklist is accurate and relevant to the CVE details provided.
\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "4a24f441-2997-45b4-a6d7-4de574716623", + "metadata": { + "tags": [] + }, + "source": [ + "#### 1.3.2 - Explore On Your Own: Different Models\n", + "\n", + "How do alternative models perform? Do any adhere more closely to the formatting instructions?" + ] + }, + { + "cell_type": "code", + "id": "bcbbb288-8aa6-41ea-ace5-292c8d288d47", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try different models\n", + "# models_to_try = [\"meta/llama3-70b-instruct\", \"meta/llama3-8b-instruct\"] #Other models go here\n", + "\n", + "# for model in models_to_try:\n", + "# print(f\"\\n----\\nModel: {model}\")\n", + "# completion = llm_client.chat.completions.create(\n", + "# model=model,\n", + "# messages=[{\"role\":\"user\",\"content\":formatted_prompt}],\n", + "# temperature=0.5,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=True\n", + "\n", + "# )\n", + "\n", + "# for chunk in completion:\n", + "# if chunk.choices[0].delta.content is not None:\n", + "# print(chunk.choices[0].delta.content, end=\"\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "945a3b2b-d397-4f85-8c79-894565ecad7c", + "metadata": { + "tags": [] + }, + "source": [ + "#### 1.3.3 - Evaluating Model Performance through Formatting Checks\n", + "\n", + "One way to to assess the model's performance is by checking its ability to adhere to our formatting instructions to output a python list.\n" + ] + }, + { + "cell_type": "code", + "id": "857dfe77-bc9c-4ca7-b5d2-ece4cf18bd09", + "metadata": { + "tags": [] + }, + "source": [ + "import ast\n", + "\n", + "\n", + "# we can evaluate if the checklist is properly formatted using this function\n", + "def is_properly_formatted_list(checklist):\n", + " try:\n", + " # Attempt to evaluate checklist as a Python literal\n", + " evaluated_checklist = ast.literal_eval(checklist)\n", + "\n", + " # Check if the evaluated object is a list\n", + " if isinstance(evaluated_checklist, list):\n", + " print(\"Checklist is properly formatted.\")\n", + " return True\n", + " else:\n", + " print(\"Checklist is not a list.\")\n", + " return False\n", + " except ValueError as e:\n", + " # Handle the case where checklist cannot be evaluated as a Python literal\n", + " print(f\"Checklist is not properly formatted: {e}\")\n", + " return False\n", + " except SyntaxError as e:\n", + " # Handle syntax errors in the checklist string\n", + " print(f\"Checklist has a syntax error: {e}\")\n", + " return False" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "cfb6596f-a607-4aff-a44c-90acb147dabf", + "metadata": { + "tags": [] + }, + "source": [ + "is_properly_formatted_list(\n", + " llm_client.chat.completions.create(\n", + " model=\"meta/llama3-70b-instruct\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}], #Prompt goes here\n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=False\n", + ").choices[0].message.content)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "f0933b63-13bb-4e57-8cf1-cb0aab3f43da", + "metadata": { + "tags": [] + }, + "source": [ + "
\n", + "If the model's output doesn't meet our expectations, what are our next steps?\n" + ] + }, + { + "cell_type": "markdown", + "id": "c3686239-80aa-49a1-91f7-5df78fb72d25", + "metadata": { + "tags": [] + }, + "source": [ + "
\n", + "\n", + "### 1.4 - One-Shot Learning\n", + "\n", + "Our prevoius examples illustrated zero-shot learning or direct prompting, where the LLM was simply given instructions and asked to follow them. The process of adding one example to the prompt or **one-shot learning** can often greatly improve performance as it is more difficult to describe the desired output than it is to show it. It's as straight forward as it sounds, add a single example of the desired output to the prompt. Let's try it.\n" + ] + }, + { + "cell_type": "code", + "id": "b58c9b36-b074-41e9-8177-a243f75a9ec1", + "metadata": { + "tags": [] + }, + "source": [ + "unparsable_list = \"\"\"- Check if the vulnerable package, PyArrow, is installed in the container.\n", + "- If the vulnerable package is installed, check the version of the package. If it is before 14.0.1, the vulnerability is present.\n", + "- Check if the container has any exposed IPC or Parquet readers.\"\"\"" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "60d44721-9d7c-4c5c-9c16-05f11a8cf8ee", + "metadata": {}, + "source": [ + "Zero-Shot Example\n" + ] + }, + { + "cell_type": "code", + "id": "6c1a8f41-5e33-49bc-aeec-7d32471f46b5", + "metadata": { + "tags": [] + }, + "source": [ + "zero_shot_template = \"\"\"Parse the following checklist's contents into a python list.\n", + "Checklist:\n", + "{checklist}\n", + "\n", + "Only provide the list as a resonse.\"\"\"\n", + "\n", + "formatted_prompt = zero_shot_template.format(checklist=unparsable_list)\n", + "\n", + "model_output = llm_client.chat.completions.create(\n", + " model=\"meta/llama3-70b-instruct\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}], \n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=False\n", + ").choices[0].message.content\n", + "\n", + "print(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "b3872ee0-cbb1-42b7-8194-c457ee606ff5", + "metadata": { + "tags": [] + }, + "source": [ + "is_properly_formatted_list(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "5d2c0ce8-6a2c-4f23-bad4-5d55731da199", + "metadata": {}, + "source": [ + "One-shot Example\n" + ] + }, + { + "cell_type": "code", + "id": "e5eda499-e858-4114-9900-01d086ccef55", + "metadata": { + "tags": [] + }, + "source": [ + "one_shot_template = \"\"\"Using the example as a guide, parse the checklist's contents into a python list.\n", + "Example Checklist:\n", + "- Check for notable vulnerable software vendors\n", + "- Consider the network exposure of your Docker container\n", + "\n", + "Example Output:\n", + "[\"Check for notable vulnerable software vendors\", \"Consider the network exposure of your Docker container\"]\n", + "\n", + "Given Checklist:\n", + "{checklist}\n", + "\n", + "Output Python List. Only provide the list as a response: \"\"\"\n", + "\n", + "formatted_prompt = one_shot_template.format(checklist=unparsable_list)\n", + "\n", + "model_output = llm_client.chat.completions.create(\n", + " model=\"meta/llama3-70b-instruct\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}],\n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=False\n", + ").choices[0].message.content\n", + "\n", + "print(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "b6299d06-e278-4372-8100-7d5f111c59cd", + "metadata": { + "tags": [] + }, + "source": [ + "is_properly_formatted_list(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "1fa97813-b21c-4445-8f8a-b99a03e03267", + "metadata": {}, + "source": [ + "#### 1.4.1 - Explore on your own: Robustness\n", + "\n", + "- How robust is the one-shot example?\n", + "\n", + "- Is it effective when the unparsable list is enumerated or bulleted instead of using dashes?\n" + ] + }, + { + "cell_type": "code", + "id": "570d2da8-b30b-47e7-895e-0f9fde2acb08", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try with an enumerated list\n", + "# enumerated_list = \"\"\"1. Check if the vulnerable package, PyArrow, is installed in the container.\n", + "# 2. If the vulnerable package is installed, check the version of the package. If it is before 14.0.1, the vulnerability is present.\n", + "# 3. Check if the container has any exposed IPC or Parquet readers.\"\"\"\n", + "\n", + "# formatted_prompt = one_shot_template.format(checklist=unparsable_list)\n", + "\n", + "# model_output = llm_client.chat.completions.create(\n", + "# model=\"meta/llama3-70b-instruct\",\n", + "# messages=[{\"role\":\"user\",\"content\":formatted_prompt}], #Prompt goes here\n", + "# temperature=0.5,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=False\n", + "# ).choices[0].message.content\n", + "# print(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "bca366ae-4557-4b9f-be6c-1aacb5e0c52f", + "metadata": {}, + "source": [ + "---\n" + ] + }, + { + "cell_type": "markdown", + "id": "d08bba90-3201-4c95-b8c4-6f4d2eb0f3a9", + "metadata": { + "tags": [] + }, + "source": [ + "### 1.5 - Few-Shot Learning and Detailed Prompts\n", + "\n", + "Prompts can be extended to be quite large, descriptive and include many examples. Below is an example of very detailed prompt that contains all the elements discussed above and more. What extra elements do you notice?\n" + ] + }, + { + "cell_type": "code", + "id": "62834ec0-ef09-4462-88e1-851066dd45cd", + "metadata": { + "tags": [] + }, + "source": [ + "few_shot_prompt_template = \"\"\"You are an expert security analyst. Your objective is to add a \"Checklist\" section containing steps to use when assessing the exploitability of a specific CVE within a containerized environment. \\\n", + "For each checklist item, start with an action verb, making it clear and actionable\n", + "\n", + "**Context**:\n", + "Not all CVEs are exploitable in a given container. By making a checklist specific to the information available for a given CVE analysts can execute the checklist to determine exploitability.\n", + "\n", + "**Example Format**:\n", + "Below is a format for examples that illustrate transforming CVE information into an exploitability assessment checklist.\n", + "\n", + "Example 1 CVE Details:\n", + "- CVE ID: CVE-2022-2309\n", + "- Description: NULL Pointer Dereference allows attackers to cause a denial of service (or application crash). This only applies when lxml up to version 4.9.1 \\\n", + "is used together with libxml2 2.9.10 through 2.9.14. libxml2 2.9.9 and earlier are not affected. It allows triggering crashes through forged input data, given a \\\n", + "vulnerable code sequence in the application. The vulnerability is caused by the iterwalk function (also used by the canonicalize function). Such code shouldn't be \\\n", + "in wide-spread use, given that parsing + iterwalk would usually be replaced with the more efficient iterparse function. However, an XML converter that serialises to \\\n", + "C14N would also be vulnerable, for example, and there are legitimate use cases for this code sequence. If untrusted input is received (also remotely) and processed via \\\n", + "iterwalk function, a crash can be triggered.\n", + "- Vulnerable Package Name: lxml, libxml2\n", + "- Vulnerable Package Version: lxml: up to 4.9.1, libxml2: 2.91.0 through 2.9.14\n", + "- CVSS3 Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H\n", + "\n", + "Example 1 Exploitability Assessment Checklist:\n", + "[\n", + "\"Check for lxml: Verify if your project uses the lxml library, which is the affected package. If lxml is not a dependency in your project, then your code is not vulnerable to this CVE.\",\n", + "\"Review Affected Versions: If lxml is used, checked the version that your project depends on. According to the vulnerability details, versions 4.9.0 and earlier are vulnerable.\",\n", + "\"Review Versions of Connected Dependencies: The package is only vulnerable if libxml 2.9.10 through 2.9.14 is also present. Check the version of libxml in the project.\",\n", + "\"Check for use of vulnerable functions: The library is vulnerable through its `iterwalk` function, which is also utilized by the `canonicalize` function. Check if either of these functions are used in your code base.\"\n", + "]\n", + "\n", + "Example 2 CVE Details:\n", + "- CVE ID: CVE-2024-23334\n", + "- Description: aiohttp is an asynchronous HTTP client/server framework for asyncio and Python. When using aiohttp as a web server and configuring static routes, \\\n", + "it is necessary to specify the root path for static files. Additionally, the option 'follow_symlinks' can be used to determine whether to follow symbolic links \\\n", + "outside the static root directory. When 'follow_symlinks' is set to True, there is no validation to check if reading a file is within the root directory. This can \\\n", + "lead to directory traversal vulnerabilities, resulting in unauthorized access to arbitrary files on the system, even when symlinks are not present. \\\n", + "Disabling `follow_symlinks` by setting `follow_symlinks = False` and using a reverse proxy are encouraged mitigations. Version 3.9.2 fixes this issue.\n", + "- Vulnerable Package Name: aiohttp\n", + "- Vulnerable Package Version: from 1.0.5 up to (excluding) 3.9.2\n", + "- CVSS3 Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N\n", + "\n", + "Example 2 Exploitability Assessment Checklist:\n", + "[\n", + " \"Check for aiohttp: Verify if your project uses the aiohttp library, which is the affected package. If aiohttp is not a dependency in your project, then your code is not vulnerable to this CVE.\",\n", + " \"Review Affected Versions: If aiohttp is used, check the version that your project depends on. According to the vulnerability details, versions from 1.0.5 up to (excluding) 3.9.2 are affected by this vulnerability.\",\n", + " \"Review Code To Check for Vulnerability Mitigation: Check if the 'follow_symlinks' option is set to False to mitigate the risk of directory traversal vulnerabilities.\"\n", + "]\n", + "\n", + "**Criteria**:\n", + "- Exploitability assessment checklists must relate to the information in the specific CVE Details.\n", + "- Exploitability assessment checklists must include checks for mitigating conditions when present in the CVE Details.\n", + "\n", + "**Procedure**:\n", + "[\n", + "\"Understand the CVE Details, description, and CVSS3 attack vector string.\",\n", + "\"Produce a CVE exploitability assessment checklist.\",\n", + "\"Format the checklist as comma separated list surrounded by square braces.\",\n", + "\"Output the checklist.\"\n", + "]\n", + "\n", + "**CVE Details:**\n", + "- CVE ID: {cve}\n", + "- Description: {cve_description}\n", + "- Vulnerable Package Name: {vuln_package}\n", + "- Vulnerable Package Version: {vuln_package_version}\n", + "- CVSS3 Vector String: {cvss3}\n", + "\n", + "**Checklist**: \n", + "\n", + "Please only provide the list as output.\"\"\"\n", + "\n", + "formatted_prompt = few_shot_prompt_template.format(**PYARROW_CVE_INTEL)\n", + "\n", + "model_output = llm_client.chat.completions.create(\n", + " model=\"meta/llama3-70b-instruct\",\n", + " messages=[{\"role\":\"user\",\"content\":formatted_prompt}],\n", + " temperature=0.5,\n", + " top_p=1,\n", + " max_tokens=1024,\n", + " stream=False\n", + ").choices[0].message.content\n", + "\n", + "print(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "b14a3924-eb83-4ce4-91d3-e9fb7f9648b8", + "metadata": { + "tags": [] + }, + "source": [ + "is_properly_formatted_list(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "f6d50410-fe09-4569-8aab-e72e4a808bc6", + "metadata": { + "tags": [] + }, + "source": [ + "#### 1.5.1 - Explore on your own\n", + "- What feedback could an expert cyber analyst give you about this output?\n", + "\n", + "\n", + "- What happens when you take a checklist item from what the model generated above and ask the model about it?" + ] + }, + { + "cell_type": "code", + "id": "d8fcbfb2-e3ca-424c-9575-db61be58bb72", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try it out\n", + "# example_checklist_item = (\n", + "# \"Check for PyArrow: Verify if your project uses the PyArrow library, which is the affected package. \"\n", + "# \"If PyArrow is not a dependency in your project, then your code is not vulnerable to this CVE.\"\n", + "# )\n", + "# print(llm_client.chat.completions.create(\n", + "# model=\"meta/llama3-70b-instruct\",\n", + "# messages=[{\"role\":\"user\",\"content\":example_checklist_item}], #Prompt goes here\n", + "# temperature=0.5,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=False\n", + "# ).choices[0].message.content)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "14d4d912-a7b0-4def-b823-0512beb770c7", + "metadata": {}, + "source": [ + "- How many examples do you think could fit in a prompt before the context is too large for the model?" + ] + }, + { + "cell_type": "code", + "id": "2f0b6274-95da-47d4-b1f9-fa30a87bd339", + "metadata": { + "tags": [] + }, + "source": [ + "# # UNCOMMENT to try it out\n", + "# # Let's try repeating the first example 14 times\n", + "# example_one_start_index = 626\n", + "# example_one_end_index = 2527\n", + "\n", + "# def repeat_substring(main_str, substring_start_index, substring_end_index, n):\n", + "# # Divide the main_str into before and after parts\n", + "# sub_str = main_str[substring_start_index:substring_end_index]\n", + "# before_part = main_str[:substring_start_index]\n", + "# after_part = main_str[substring_end_index:]\n", + "\n", + "# # Repeat sub_str n times\n", + "# repeated_sub_str = sub_str * n\n", + "\n", + "# # Concatenate before part, repeated sub_str, and after part\n", + "# result = before_part + repeated_sub_str + after_part\n", + "# return result\n", + "\n", + "# updated_prompt = repeat_substring(few_shot_prompt_template, example_one_start_index, example_one_end_index, 14)\n", + "\n", + "# model_output = llm_client.chat.completions.create(\n", + "# model=\"meta/llama3-8b-instruct\",\n", + "# messages=[{\"role\":\"user\",\"content\":updated_prompt}], #Prompt goes here\n", + "# temperature=0.5,\n", + "# top_p=1,\n", + "# max_tokens=1024,\n", + "# stream=False\n", + "# ).choices[0].message.content\n", + "# print(model_output)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "86b93294", + "metadata": {}, + "source": [ + "Do you see an error indicating that the context is too long for the model to handle?
\n", + "Try different values of `n` to see where the boundary of context length lies." + ] + }, + { + "cell_type": "markdown", + "id": "6228cdd9-efd8-4d59-8320-c462a4a6552d", + "metadata": { + "tags": [] + }, + "source": [ + "---\n", + "### 1.6 - Evaluation Strategies\n" + ] + }, + { + "cell_type": "markdown", + "id": "48198ef0-ec03-43af-a050-bfc9fa4f0ff0", + "metadata": {}, + "source": [ + "**A Note On Evaluation Strategies**\n", + "\n", + "Evaluating model performance on desired metrics such as **creates a properly formatted list** is relatively straightforward and traditional accuracy measurements (ie. properly formatted outputs/total outputs) can be used.\n", + "\n", + "For evaluating more subjective outcomes such as **completeness of the checklist** there are other strategies that can be explored for task-specific LLMs.\n", + "\n", + "During this initial experimental stage, it makes sense to have expert humans review outputs to determine the model's performance. A common pattern that emerges when developing and evaluating cybersecurity use cases around LLMs is as follows:\n", + "\n", + "1. Experiment using a few golden examples to determine feasibility, and evaluate candidate models and prompts by hand\n", + "2. Collect feedback on initial model outputs from experts and use this feedback to create a larger dataset\n", + "3. Use the newly created larger dataset from experts to create use-case-specific training and benchmark datasets\n", + "\n", + "Since getting these initial results into the hands of experts for evaluation is oftentimes a crucial component for obtaining a larger benchmark dataset, we will focus on quickly and easily building out the end-to-end pipeline for this use case example.\n", + "\n", + "---\n" + ] + }, + { + "cell_type": "markdown", + "id": "0afdc87a", + "metadata": {}, + "source": [ + "
\n", + "Note: Please wait here until instructed to continue with running the notebook.\n", + "
\n", + "\n", + "## 2 - Prototyping\n", + "\n", + "Now that we have the task generation for this workflow ready, how can we automate getting the answers for our checklist items?\n", + "\n", + "### 2.1 - Overview\n", + "\n", + "It is possible to build a language model-based system that accesses external knowledge sources to complete tasks. In [Section 1.3](#1.3---Prompt-Templating), we added additional CVE details into the prompt by hand. While this strategy can be effective for adding additional context for very specific items like CVE Details, it requires a priori knowledge of what details to include (like those from NVD). When you would like to help your LLM with its query by adding more context in real-time, you're ready for RAG (Retrieval Augmented Generation).\n", + "\n", + "When a query or checklist item is posed to an LLM equipped with RAG, the model first consults the vector database to find relevant information related to the query. This retrieved data is then combined with the original question and fed back into the LLM. With this enriched context, the LLM can generate a more accurate and informed response, potentially including evidence or reasoning based on the newly incorporated data. This approach not only improves the quality of the LLM's outputs but also gives our tool access to project- and container-specific information to determine CVE exploitability.\n", + "\n", + "### 2.2 - Building the Vector Database\n", + "\n", + "In addition to having a query and LLM, RAG requires additional information to be stored in a vector database. One mechanism of finding the proper information from the database is to first embed the query into the same vector space and retrieve the top most similar items via a distance metric. The additional information is then presented in the prompt of the LLM. The neighboring vectors in the database are said to be \"semantically similar\" to the query and likely relevant.\n", + "\n", + "For our demonstration purposes, we would like our LLM to be able to access the code repository of the project we're interested in checking for exploitable CVEs. The first step is transforming the specific repo into a vector database. Before that, lets pull a shallow clone of the `Morpheus 24.03` branch from GitHub and use that as the codebase for this example. We'll also set up a logging directory for the Morpheus LLM Client logs.\n" + ] + }, + { + "cell_type": "code", + "id": "45ec2c86-8de5-497e-9fb9-7ddfd27f0d13", + "metadata": { + "tags": [] + }, + "source": [ + "%%capture\n", + "\n", + "! git clone --depth 1 -b branch-24.03 https://github.com/nv-morpheus/Morpheus.git\n", + "! mkdir /root/.cache/morpheus \n", + "! mkdir /root/.cache/morpheus/log" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "a0c5175d", + "metadata": { + "tags": [] + }, + "source": [ + "from cyber_dev_day.embeddings import create_code_embedding\n", + "from langchain.embeddings.huggingface import HuggingFaceEmbeddings\n", + "\n", + "# Create the embedding object that will be used to generate the embeddings\n", + "embeddings = HuggingFaceEmbeddings(model_name=\"sentence-transformers/all-mpnet-base-v2\",\n", + " model_kwargs={\"device\": \"cuda\"},\n", + " show_progress=True)\n", + "\n", + "# Create a vector database of the code using the supplied embedding function. The returned value will be a\n", + "# FaissVectorDatabase object.\n", + "# NOTE: This may take a few minutes to run.\n", + "faiss_vdb = create_code_embedding(code_dir=os.path.join(os.getenv(\"MORPHEUS_ROOT\"), \"notebooks\", \"Morpheus\"),\n", + " embedding=embeddings,\n", + " include_notebooks=False,\n", + " exclude=[\".cache/**/*.py\", \"build*/**/*.py\"])\n", + "\n", + "# Save the vector database to disk\n", + "code_faiss_dir = os.path.join(os.getenv(\"MORPHEUS_ROOT\"), \".tmp\", \"morpheus_code_faiss\")\n", + "\n", + "faiss_vdb.save_local(code_faiss_dir)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "eb0cd628", + "metadata": {}, + "source": [ + "
\n", + "Note: Please wait here until instructed to continue with running the notebook.\n", + "
\n", + "\n", + "### 2.3 - Running a RAG Pipeline with Morpheus\n", + "\n", + "Now that we have built a vector database to provide external knowledge for the LLM, we need to make a tool that can query the vector database, add the information to the prompt, and execute the LLM query. There are many tools out there that can perform this task, but in this lab, we will be using NVIDIA Morpheus.\n", + "\n", + "#### 2.3.1 - Morpheus Overview\n", + "\n", + "NVIDIA Morpheus is an open AI application framework that aids cybersecurity experts in building high-performance pipelines for cybersecurity workflows. Morpheus is well suited for building a RAG pipeline due to its LLM Engine, which is specifically designed to aid in integrating LLMs into high throughput and low latency pipelines. A complete guide covering Morpheus is beyond the scope of this notebook but more information on Morpheus can be found at the following locations:\n", + "\n", + "- Documentation: https://docs.nvidia.com/morpheus/index.html\n", + "- Github Repo: https://github.com/nv-morpheus/Morpheus\n", + "- Morpheus Examples: https://github.com/nv-morpheus/Morpheus/tree/branch-24.03/examples\n", + "\n", + "To start building a Morpheus pipeline, the first step is always to create a configuration object. The configuration object controls global options for the pipeline such as batch size, number of threads, logging, and more. For our needs, we can use the default values and only need to create the object which we will be passing to each pipeline.\n" + ] + }, + { + "cell_type": "code", + "id": "ec9cbc52", + "metadata": { + "tags": [] + }, + "source": [ + "from morpheus.config import Config\n", + "from morpheus.config import PipelineModes\n", + "\n", + "# Create the pipeline config\n", + "pipeline_config = Config()\n", + "pipeline_config.mode = PipelineModes.OTHER" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "a7829100", + "metadata": {}, + "source": [ + "#### 2.3.2 - Building a Morpheus RAG Pipeline\n", + "\n", + "Below, we will build a pipeline that uses Morpheus to answer questions about the code in the repository that we created a vector database for. This works by using the `LLMEngine` in Morpheus with a `RAGNode`.\n" + ] + }, + { + "cell_type": "code", + "id": "3833deda", + "metadata": { + "tags": [] + }, + "source": [ + "from textwrap import dedent\n", + "\n", + "from cyber_dev_day.config import EngineConfig\n", + "from cyber_dev_day.config import LLMModelConfig\n", + "from cyber_dev_day.config import NVFoundationLLMModelConfig\n", + "from cyber_dev_day.nim_llm_service import NIMLLMService\n", + "from cyber_dev_day import config\n", + "from cyber_dev_day.llm_service import LLMService \n", + "from cyber_dev_day.faiss_vdb_service import FaissVectorDBService\n", + "\n", + "from morpheus._lib.llm import LLMEngine\n", + "from morpheus.llm.nodes.extracter_node import ExtracterNode\n", + "from morpheus.llm.nodes.rag_node import RAGNode\n", + "from morpheus.llm.task_handlers.simple_task_handler import SimpleTaskHandler\n", + "from morpheus.messages import ControlMessage\n", + "from morpheus.pipeline.linear_pipeline import LinearPipeline\n", + "from morpheus.stages.input.in_memory_source_stage import InMemorySourceStage\n", + "from morpheus.stages.llm.llm_engine_stage import LLMEngineStage\n", + "from morpheus.stages.output.in_memory_sink_stage import InMemorySinkStage\n", + "from morpheus.stages.preprocess.deserialize_stage import DeserializeStage\n", + "from morpheus.utils.concat_df import concat_dataframes\n", + "\n", + "\n", + "def _build_rag_llm_engine(model_config: LLMModelConfig):\n", + "\n", + " engine = LLMEngine()\n", + "\n", + " # Create an extracter node to pull the specified input from the DataFrame\n", + " engine.add_node(\"extracter\", node=ExtracterNode())\n", + "\n", + " prompt = dedent(\"\"\"\n", + " You are a helpful assistant. Given the following background information:\n", + " {% for c in contexts -%}\n", + " Source File: {{ c.metadata.source }}\n", + " Source File Language: {{ c.metadata.language }}\n", + " Source Content:\n", + " ```\n", + " {{ c.page_content }}\n", + " ```\n", + " {% endfor %}\n", + "\n", + " Please answer the following question:\n", + " {{ query }}\n", + " \"\"\").strip(\"\\n\")\n", + "\n", + " # Create a service to query the vector database we created from the python source code\n", + " vector_service = FaissVectorDBService(code_faiss_dir, embeddings=embeddings)\n", + " vdb_resource = vector_service.load_resource()\n", + "\n", + " # Create an LLM service using the model configuration options in the LLM Model Config\n", + " llm_service = LLMService.create(model_config.service.type, **model_config.service.model_dump(exclude={\"type\"}))\n", + " llm_client = llm_service.get_client(**model_config.model_dump(exclude={\"service\"}))\n", + "\n", + " # Async wrapper around embeddings\n", + " async def calc_embeddings(texts: list[str]) -> list[list[float]]:\n", + " return embeddings.embed_documents(texts)\n", + "\n", + " # Add a RAG Node to the engine which will use the prompt, vector database, emebddings and LLM\n", + " engine.add_node(\"rag\",\n", + " inputs=[\"/extracter\"],\n", + " node=RAGNode(prompt=prompt,\n", + " vdb_service=vdb_resource,\n", + " embedding=calc_embeddings,\n", + " llm_client=llm_client))\n", + "\n", + " # Final step of every LLM Engine is to turn the output data back into a Control Message for the rest of the pipeline\n", + " engine.add_task_handler(inputs=[\"/rag\"], handler=SimpleTaskHandler())\n", + "\n", + " return engine\n", + "\n", + "\n", + "# Define a function that will build and run the pipeline given a configuration and question input\n", + "async def run_rag_pipeline(p_config: Config, model_config: LLMModelConfig, question: str):\n", + " source_dfs = [\n", + " cudf.DataFrame({\"questions\": [question]}),\n", + " ]\n", + "\n", + " # Create a completion task to be used by the DeserializeStage. This indicates which columns to use from the\n", + " # dataframe\n", + " completion_task = {\"task_type\": \"completion\", \"task_dict\": {\"input_keys\": [\"questions\"], }}\n", + "\n", + " pipe = LinearPipeline(p_config)\n", + "\n", + " # Create a source object which will emit our dataframe into the pipeline\n", + " pipe.set_source(InMemorySourceStage(p_config, dataframes=source_dfs))\n", + "\n", + " # The deserialize stage will take the dataframe and convert it into a ControlMessage object\n", + " pipe.add_stage(\n", + " DeserializeStage(p_config, message_type=ControlMessage, task_type=\"llm_engine\", task_payload=completion_task))\n", + "\n", + " # Add the LLM Engine stage to the pipeline. This executes our RAG query and runs the LLM model\n", + " pipe.add_stage(LLMEngineStage(p_config, engine=_build_rag_llm_engine(model_config)))\n", + "\n", + " # Add a sink to the pipeline to capture the output of the pipeline\n", + " sink = pipe.add_stage(InMemorySinkStage(p_config))\n", + "\n", + " # Run the pipeline. This will complete once all messages have been processed\n", + " await pipe.run_async()\n", + "\n", + " messages = sink.get_messages()\n", + " responses = concat_dataframes(messages)\n", + "\n", + " # The responses are quite long, when debug is enabled disable the truncation that pandas and cudf normally\n", + " # perform on the output\n", + " pd.set_option(\"display.max_colwidth\", None)\n", + " logger.info(\"Response:\\n%s\" % (responses[\"response\"].iloc[0], ))" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "dd9f1092", + "metadata": { + "tags": [] + }, + "source": [ + "model_config = config.NIMModelConfig.model_validate({\n", + " \"service\": {\n", + " \"type\": \"NIM\", \"api_key\": None\n", + " },\n", + " \"base_url\": \"https://integrate.api.nvidia.com/v1\",\n", + " \"model_name\": \"meta/llama3-70b-instruct\",\n", + " \"temperature\": 0.0\n", + "}) #API key here is an environment variable, so we don't need to specify it explicitly\n", + "\n", + "# Run the Pipeline\n", + "await run_rag_pipeline(pipeline_config, model_config, \"Does the code repo import the `pyarrow_hotfix` package from the `morpheus` root package?\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "0380153a", + "metadata": {}, + "source": [ + "#### 2.3.3 - RAG Limitations\n", + "\n", + "Using the pipeline we built, we can now ask questions about the code in the repository and the LLM will be able to use the vector database to answer them. However, what happens if we need to ask questions about code that is not in the vector database? For example, what if we needed to ask questions about the dependencies that the code uses? Would the LLM be able to answer these questions? Let's try it out by re-running our RAG pipeline with a more complex question:\n" + ] + }, + { + "cell_type": "code", + "id": "506b5fb3", + "metadata": { + "tags": [] + }, + "source": [ + "# Run the Pipeline\n", + "await run_rag_pipeline(pipeline_config, model_config, \"Does the code repo use `langchain` functions which are deprecated?\")" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "4abd8482", + "metadata": {}, + "source": [ + "It's likely that the model was not able to determine the answer to this question because it would need additional information. Depending on the model used, you might see output similar to:\n", + "\n", + "```\n", + "Without further information about the `langchain` package or its documentation, it's difficult to determine if any specific functions or methods used in the code are deprecated.\n", + "```\n", + "\n", + "How would we go about solving this problem?\n" + ] + }, + { + "cell_type": "markdown", + "id": "c5fb24c7", + "metadata": {}, + "source": [ + "### 2.4 - Running the CVE Pipeline with Morpheus\n", + "\n", + "#### 2.4.1 - Answering Complex Questions with RAG + LLM Agents\n", + "\n", + "To answer a question about the existence of deprecated `langchain` functions, the model needs to look up versions of the packages in our container or project. We can add an additional knowledge source such as a Software Bill of Materials (SBOM). With multiple tools/knowledge sources- `SBOM Package Checker` and `Docker Container Code QA System` we need a new framework to allow our LLM to choose what tools it needs to use and synthesize the responses. One method we can use is [LangChain agents](https://python.langchain.com/docs/modules/agents/). \n", + "\n", + "An agent in this sense is an LLM that has \"agency\" to determine what sources of information it needs to retrieve to answer questions. This can be achieved through prompting. The most simplistic prompt to use to turn an LLM into an agent with tool usage might look like this:\n", + "\n", + "```\n", + "You are a helpful assistant. Help the user answer any questions.\n", + "\n", + "You have access to the following tools:\n", + "\n", + "{tools}\n", + "\n", + "In order to use a tool, you can use and tags.\n", + "You will then get back a response in the form \n", + "When you are done, respond with a final answer between . \n", + "\n", + "Question: {input}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "1896fa18", + "metadata": {}, + "source": [ + "Ideally, with just one round of query-> tool-> observation-> final answer, the LLM will get the information it needs to answer simple queries such as `What version of PyArrow is in the repo?`\n", + "\n", + "But what about more complex queries such as `Does the code repo use langchain functions which are deprecated?` \n", + "This query would require the LLM to first find what functions are deprecated before searching the code base for them. We would prompt the LLM to use a series of steps (repeated N times): Thought, Action, and Observation. This process loop of reasoning and acting is called a [ReAct Agent](https://react-lm.github.io/). In practice, it could be like this:\n", + "\n", + "```\n", + "query: Does the morpheus code repo use langchain functions which are deprecated?\n", + "> Entering new AgentExecutor chain...\n", + "I need to check the langchain version in the container's SBOM and the deprecated source code functions.\n", + "Action: SBOM Package Checker\n", + "Action Input: langchain\n", + "Observation: 0.1.12\n", + "Thought: The langchain version in the container is 0.1.12.\n", + "Thought: I need to check the langchain source code for deprecated functions.\n", + "Action: Docker Container Code QA System\n", + "Action Input: Does the repo use the format_tool_to_openai_function or __call__ from langchain?\n", + "Observation: No, the repo does not use format_tool_to_openai_function or __call__ from langchain.\n", + "Thought: I now know the final answer.\n", + "Final Answer: The morpheus code repo does not use langchain functions which are deprecated.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "396f48d3", + "metadata": {}, + "source": [ + "How can we incorporate these powerful ReAct agents and their tools into an end-to-end pipeline?" + ] + }, + { + "cell_type": "markdown", + "id": "ffcdcfb0", + "metadata": {}, + "source": [ + "#### 2.4.2 - The Morpheus CVE Pipeline\n", + "\n", + "To convert our RAG pipeline into a CVE pipeline, all we need to do is update the LLM engine to run the CVE steps instead of a single RAG node as before." + ] + }, + { + "cell_type": "code", + "id": "a16bf979", + "metadata": { + "tags": [] + }, + "source": [ + "from cyber_dev_day.pipeline_utils import build_cve_llm_engine\n", + "\n", + "from morpheus.messages import ControlMessage\n", + "from morpheus.pipeline.linear_pipeline import LinearPipeline\n", + "from morpheus.stages.input.in_memory_source_stage import InMemorySourceStage\n", + "from morpheus.stages.llm.llm_engine_stage import LLMEngineStage\n", + "from morpheus.stages.output.in_memory_sink_stage import InMemorySinkStage\n", + "from morpheus.stages.preprocess.deserialize_stage import DeserializeStage\n", + "from morpheus.utils.concat_df import concat_dataframes\n", + "\n", + "\n", + "async def run_cve_pipeline(p_config: Config, e_config: EngineConfig, input_cves: list[str], retry_bad_input = True):\n", + " source_dfs = [cudf.DataFrame({\"cve_info\": input_cves})]\n", + "\n", + " # Create a completion task to be used by the DeserializeStage. This indicates which columns to use from the\n", + " # dataframe\n", + " completion_task = {\"task_type\": \"completion\", \"task_dict\": {\"input_keys\": [\"cve_info\"], }}\n", + "\n", + " pipe = LinearPipeline(p_config)\n", + "\n", + " # Create a source object which will emit our dataframe into the pipeline\n", + " pipe.set_source(InMemorySourceStage(p_config, dataframes=source_dfs))\n", + "\n", + " # The deserialize stage will take the dataframe and convert it into a ControlMessage object\n", + " pipe.add_stage(\n", + " DeserializeStage(p_config, message_type=ControlMessage, task_type=\"llm_engine\", task_payload=completion_task))\n", + "\n", + " # Add the LLM Engine stage to the pipeline. This executes our CVE workflow and runs the LLM model\n", + " pipe.add_stage(LLMEngineStage(p_config, engine=build_cve_llm_engine(e_config, retry_bad_input)))\n", + "\n", + " # Add a sink to the pipeline to capture the output of the pipeline\n", + " sink = pipe.add_stage(InMemorySinkStage(p_config))\n", + "\n", + " # Run the pipeline. This will complete once all messages have been processed\n", + " await pipe.run_async()\n", + "\n", + " messages = sink.get_messages()\n", + " responses = concat_dataframes(messages)\n", + "\n", + " logger.info(\"Received %s responses:\\n%s\", len(messages), responses[[\"checklist\", \"response\"]].to_json(indent=2))" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "bf81f7ed", + "metadata": {}, + "source": [ + "#### 2.4.3 - The Engine Config\n", + "\n", + "The `EngineConfig` object controls options about the CVE pipeline we are building. It allows us to contain all of the settings in a single object which can be easily used from many different classes which will be used to construct the pipeline. Below we will create the default configuration we will be using for the rest of the notebook.\n" + ] + }, + { + "cell_type": "code", + "id": "b628e418", + "metadata": { + "tags": [] + }, + "source": [ + "from cyber_dev_day.config import EngineConfig\n", + "\n", + "# Create the engine configuration\n", + "engine_config = EngineConfig.model_validate({\n", + " \"checklist\": {\n", + " \"model\": {\n", + " \"service\": {\n", + " \"type\": \"NIM\", \"api_key\": None\n", + " },\n", + " \"base_url\": \"https://integrate.api.nvidia.com/v1\",\n", + " \"model_name\": \"meta/llama3-70b-instruct\",\n", + " \"temperature\": 0\n", + " }\n", + " },\n", + " \"agent\": {\n", + " \"model\": {\n", + " \"service\": {\n", + " \"type\": \"NIM\", \"api_key\": None\n", + " },\n", + " \"base_url\": \"https://integrate.api.nvidia.com/v1\",\n", + " \"model_name\": \"meta/llama3-70b-instruct\",\n", + " \"temperature\": 0.02\n", + " },\n", + " \"sbom\": {\n", + " \"data_file\":\n", + " os.path.join(os.getenv(\"MORPHEUS_ROOT\", \"../\"),\n", + " \"data\",\n", + " \"morpheus_24.03-runtime_sbom.csv\")\n", + " },\n", + " \"code_repo\": {\n", + " \"faiss_dir\": code_faiss_dir, \"embedding_model_name\": \"sentence-transformers/all-mpnet-base-v2\"\n", + " }\n", + " }\n", + "})" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "09f759e4-fc8c-4c84-ba15-3f3408a2bff3", + "metadata": { + "tags": [] + }, + "source": [ + "# Print the current configuration object\n", + "print(engine_config.model_dump_json(indent=2))" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "806649e4", + "metadata": {}, + "source": [ + "#### 2.4.4 - Running the Pipeline\n", + "\n", + "Now that the pipeline has been defined and the configuration variables have been created, it's time to run the pipeline. The final step is to convert the PyArrow intel dictionary into a single string that our `run_cve_pipeline` function accepts using a template `cve_details_template`. To simplify converting intel dictionaries into strings in the rest of the notebook, we will reuse this template." + ] + }, + { + "cell_type": "code", + "id": "001ee70c", + "metadata": { + "scrolled": true, + "tags": [] + }, + "source": [ + "# Create a template to generate the cve_details from an intel dictionary\n", + "cve_details_template = \"\"\"- CVE ID: {cve}\n", + "- Description: {cve_description}\n", + "- Vulnerable Package Name: {vuln_package}\n", + "- Vulnerable Package Version: {vuln_package_version}\n", + "- CVSS3 Vector String: {cvss3}\"\"\"\n", + "\n", + "# Generate the CVE details from the pyarrow intel\n", + "cve_details = cve_details_template.format(**PYARROW_CVE_INTEL)\n", + "\n", + "# Now run the pipeline with a specified CVE description\n", + "await run_cve_pipeline(pipeline_config, engine_config, [cve_details], retry_bad_input=False)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "8c4b8a57", + "metadata": {}, + "source": [ + "The output of the pipeline should be similar in theme to the following: \n", + "```\n", + "Received 1 responses:\n", + "{\n", + " \"checklist\":{\n", + " \"0\":[\n", + " \"Check for PyArrow: Verify if your project uses the PyArrow library, which is the affected package. If PyArrow is not a dependency in your project, then your code is not vulnerable to this CVE.\",\n", + " \"Review Affected Versions: If PyArrow is used, check the version that your project depends on. According to the vulnerability details, versions before 14.0.1 are vulnerable.\",\n", + " \"Review Code To Check for Deserialization of Untrusted Data: Check if the IPC and Parquet readers are used to deserialize untrusted data, which can lead to arbitrary code execution.\",\n", + " \"Check for Mitigation: If upgrading to PyArrow 14.0.1 or later is not possible, check if the `pyarrow-hotfix` package is imported to disable the vulnerability on older PyArrow versions.\"\n", + " ]\n", + " },\n", + " \"response\":{\n", + " \"0\":[\n", + " \"Yes, the project uses the PyArrow library, which is the affected package.\",\n", + " \"Yes, the Docker container is using a vulnerable version of PyArrow (11.0.0).\",\n", + " \"No, the IPC and Parquet readers are not used to deserialize untrusted data.\",\n", + " \"Yes, the `pyarrow-hotfix` package is imported to disable the vulnerability on older PyArrow versions.\"\n", + " ]\n", + " }\n", + "}\n", + "```\n", + "In the output, we can see the output from the first model, which will be the generated checklist items, and the output of each agent, which will be the response to each checklist item. Looking at the checklist items and answers, we can see that the model has successfully determined that the project is vulnerable to the CVE.\n", + "\n", + "**NOTE**: Depending on your choice for the Agent or Checklist model, you will see different outputs that can vary in quality quite drastically. Try and explore a few different model choices and temperatures to explore what that looks like. You may also find some inconsistency in results when keeping your parameters constant. This stochasticity is a natural occurence with LLMs, and can be mitigated with prompt engineering or fine tuning.\n", + "\n", + "#### 2.4.5 - Hitting the Limits of the LLMs\n", + "\n", + "While LLMs can work well for many tasks, they are not perfect. They can fail on seemingly simple tasks, get into a loop, or not follow the output formatting correctly. These edge cases can be hard to catch and can be difficult to debug. For example, if we use the below prompt about Log4j and change the model we use for the Agent, what happens when we run the pipeline?\n" + ] + }, + { + "cell_type": "code", + "id": "1a7e791c", + "metadata": { + "scrolled": true, + "tags": [] + }, + "source": [ + "# Generate the CVE details for the log4j intel\n", + "cve_details=cve_details_template.format(**LOG4J_CVE_INTEL)\n", + "\n", + "# Create the engine configuration\n", + "suboptimal_engine_config = EngineConfig.model_validate({\n", + " \"checklist\": {\n", + " \"model\": {\n", + " \"service\": {\n", + " \"type\": \"NIM\", \"api_key\": None\n", + " },\n", + " \"base_url\": \"https://integrate.api.nvidia.com/v1\",\n", + " \"model_name\": \"meta/llama3-70b-instruct\",\n", + " \"temperature\": 0\n", + " }\n", + " },\n", + " \"agent\": {\n", + " \"model\": {\n", + " \"service\": {\n", + " \"type\": \"NIM\", \"api_key\": None\n", + " },\n", + " \"base_url\": \"https://integrate.api.nvidia.com/v1\",\n", + " \"model_name\": \"mistralai/mixtral-8x7b-instruct-v0.1\",\n", + " \"temperature\": 0.02\n", + " },\n", + " \"sbom\": {\n", + " \"data_file\":\n", + " os.path.join(os.getenv(\"MORPHEUS_ROOT\", \"../\"),\n", + " \"data\",\n", + " \"morpheus_24.03-runtime_sbom.csv\")\n", + " },\n", + " \"code_repo\": {\n", + " \"faiss_dir\": code_faiss_dir, \"embedding_model_name\": \"sentence-transformers/all-mpnet-base-v2\"\n", + " }\n", + " }\n", + "})\n", + "\n", + "# Now run the pipeline with a specified CVE description\n", + "await run_cve_pipeline(pipeline_config, suboptimal_engine_config, [cve_details], retry_bad_input=False)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "9e8c30da", + "metadata": {}, + "source": [ + "When we run the pipeline with the Log4j example, it hits an exception instead of running the pipeline to completion. The error message is `Error running agent: An output parsing error occurred` because the agent was not able to reason through the checklist while following LangChain's formatting guidelines. If we look closer, we can see that the model generated the following output for each checklist item:\n", + "```\n", + "[\n", + " \"Error running agent: An output parsing error occurred. In order to pass this error back to the agent and have it try again, pass `handle_parsing_errors=True` to the AgentExecutor. This is the error: Could not parse LLM output: ` I need to check if the log4j library is present in the Docker`\",\n", + " \"Error running agent: An output parsing error occurred. In order to pass this error back to the agent and have it try again, pass `handle_parsing_errors=True` to the AgentExecutor. This is the error: Could not parse LLM output: ` To answer this question, I need to find out which version of log4j`\",\n", + " \"Error running agent: An output parsing error occurred. In order to pass this error back to the agent and have it try again, pass `handle_parsing_errors=True` to the AgentExecutor. This is the error: Could not parse LLM output: ` To answer this question, I need to inspect the log4j configuration within the`\",\n", + " \"Error running agent: An output parsing error occurred. In order to pass this error back to the agent and have it try again, pass `handle_parsing_errors=True` to the AgentExecutor. This is the error: Could not parse LLM output: ` To answer this question, I need to check if the Docker container uses log`\"\n", + " ]\n", + "```\n", + "\n", + "Such errors can be hard to debug as it is explicit why a seemingly innocuous sentence about a thought leads to a parsing error. The reason this occurs is because the LangChain Zero Shot Agent requires every response from the Agent to always end with either a request for an `Action` or a `Final Answer`. We see above that the response contains neither. This occurs despite us explicitly asking the agent to follow those guidelines, as is evident in the `cyber_dev_day.pipeline_utils.build_agent_executor` method as follows:\n", + "\n", + "```\n", + " Action input must only contain the exact input, do not provide any text following that in your response. Always end your response with either an action, or a final answer.\n", + "```\n", + "\n", + "Careful debugging of such output is critical, and some strategies for preventing such errors could include few-shot prompting techniques, model fine-tuninging, or changing the choice of our model.\n", + "\n", + "
\n", + "Note: Please wait here until instructed to continue with running the notebook.\n", + "
\n", + "\n", + "## 3 - Beyond Prototyping\n", + "\n", + "Up until now, we have been using the pipeline we built to answer questions about the code in the repository. While this works for a few hand picked use cases, it is not suitable to deploy into a production environment for several reasons:\n", + "\n", + "1. The LLM models fail to work on some questions which can generate errors in the pipeline\n", + " - Since the pipeline chains many LLM calls together, a single error can cause the entire pipeline to fail. For a production environment, we would need to handle these errors more gracefully or improve the model to reduce the number of errors.\n", + "2. The pipeline is not optimized for performance\n", + " - The pipeline is slow to run, because each model needs to be executed sequentially. For a production environment, we would need to optimize the pipeline to handle multiple requests at once.\n", + "3. The pipeline cannot be easily integrated into other systems\n", + " - The pipeline is a standalone script which reads from a single file and needs to be run manually. For a production environment, the pipeline would need to be integrated with other systems, such as a web server or a chatbot.\n", + "\n", + "In this section, we will address some of the limitations we encountered in the previous section and discuss how we can overcome them utilizing NIM and Morpheus.\n" + ] + }, + { + "cell_type": "markdown", + "id": "78a826b5", + "metadata": {}, + "source": [ + "### 3.1 - Scaling the Pipeline\n", + "\n", + "When running pipelines which utilize LLMs, it's important to understand how the LLMs are executed to parallelize their execution as much as possible. This is because LLMs can take a long time to run, as low as a few hundred milliseconds and upwards of a few seconds. Running LLMs serially can compound those runtimes, leading to execution times that grow linearly with the number of LLM requests. A simple diagram of the execution of LLMs for our CVE pipeline is shown below:\n", + "\n", + "![Single CVE - Serial](./images/single_cve_serial.jpg)\n", + "\n", + "In the diagram above, we can see that the LLMs are executed serially, one after the other. This is not ideal as the execution time of the pipeline is directly proportional to the number of LLMs that are executed. However, there is no dependency between the LLM calls in each of the checklist items. This means that we can parallelize the execution of the LLMs to reduce the overall execution time of the pipeline. A simple diagram of the parallel execution of LLMs for our CVE pipeline is shown below:\n", + "\n", + "![Single CVE - Parallel](./images/single_cve_parallel.jpg)\n", + "\n", + "In the diagram above, we can see that the total execution time has been reduced as the checklist agent LLMs are executed in parallel. The total execution time is now the maximum time taken to execute any of the LLM agent chains. This is a significant improvement over the serial execution of the LLMs. But what happens if we need to run the entire pipeline for multiple CVEs? A naive approach would be to run the pipeline for each CVE serially, which is shown below:\n", + "\n", + "![Multiple CVE - Serial](./images/multiple_cve_serial.jpg)\n", + "\n", + "With most LLM libraries, this is the default behavior and improving on this requires more complex solutions such as multiprocessing or distributed workers. However, with Morpheus, this is trivial since Morpheus benefits from pipeline parallelism where each message is processed in an assembly line fashion. This means that we can start processing the next message before the previous one is even completed. A simple diagram of the parallel execution of the pipeline for multiple CVEs is shown below:\n", + "\n", + "![Multiple CVE - Parallel](./images/multiple_cve_parallel.jpg)\n" + ] + }, + { + "cell_type": "code", + "id": "895f9bcf", + "metadata": { + "scrolled": true, + "tags": [] + }, + "source": [ + "# Create multiple CVE requests\n", + "cves = [\n", + " cve_details_template.format(**PYARROW_CVE_INTEL),\n", + " cve_details_template.format(**LOG4J_CVE_INTEL),\n", + "] * 2\n", + "\n", + "await run_cve_pipeline(pipeline_config, engine_config, cves)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "c266d439", + "metadata": { + "tags": [] + }, + "source": [ + "If you look at the above output, you should see a section that looks like the following:\n", + "\n", + "```\n", + "> Entering new AgentExecutor chain...\n", + "\n", + "> Entering new AgentExecutor chain...\n", + "\n", + "> Entering new AgentExecutor chain...\n", + "\n", + "> Entering new AgentExecutor chain...\n", + "\n", + "> Entering new AgentExecutor chain...\n", + "```\n", + "\n", + "Because each executor chain is being started before the previous one completes, they are all running in parallel. But can we verify that this is actually leading to a performance improvement? Let's run the pipeline for a single CVE and multiple CVEs and compare their execution time.\n" + ] + }, + { + "cell_type": "code", + "id": "b1f51590", + "metadata": { + "tags": [] + }, + "source": [ + "from morpheus.utils.logging_timer import log_time\n", + "\n", + "# Update the agent config to disable verbose logging\n", + "non_verbose_config = engine_config.model_copy(deep=True)\n", + "non_verbose_config.agent.verbose = False\n", + "\n", + "# Disable the logger to make it easer to see the timings\n", + "parent_logger: logging.Logger = logger.parent\n", + "saved_level = parent_logger.level\n", + "parent_logger.setLevel(logging.ERROR)\n", + "\n", + "execution_times: dict[int, float] = {}\n", + "\n", + "for count in [1, 5, 10]:\n", + "\n", + " start_time = time.time()\n", + "\n", + " with log_time(print, count=count, msg=\"Executing {count} CVE(s). Total: {duration} ms, Average: {ms_per_count} ms\"):\n", + " await run_cve_pipeline(pipeline_config, non_verbose_config, [cves[0]] * count, retry_bad_input=True)\n", + "\n", + " execution_times[count] = time.time() - start_time\n", + "\n", + "parent_logger.setLevel(saved_level)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "138ebec5", + "metadata": {}, + "source": [ + "Your actual execution time may differ, but it should look something like the following:\n", + "\n", + "```\n", + "Executing 1 CVE(s). Total: 44263.65375518799 ms, Average: 44263.65375518799 ms\n", + "Executing 5 CVE(s). Total: 66988.19637298584 ms, Average: 13397.639274597168 ms\n", + "Executing 10 CVE(s). Total: 62277.28486061096 ms, Average: 6227.728486061096 ms\n", + "```\n", + "\n", + "As you can see, the average execution time per CVE actually goes down as we increase the number of pipeline runs due to the fact that they are being run in parallel. To get an idea of how well the pipeline scales, we can make a plot of the CVE count vs runtimes for the pipeline." + ] + }, + { + "cell_type": "code", + "id": "e84b6723", + "metadata": { + "tags": [] + }, + "source": [ + "# importing matplotlib module\n", + "from matplotlib import pyplot as plt\n", + "\n", + "# Function to plot\n", + "plt.plot(execution_times.keys(),\n", + " list(\n", + " zip(execution_times.values(), [execution_times[1] * x for x in execution_times.keys()],\n", + " [execution_times[1] for _ in execution_times.keys()])),\n", + " label=[\"actual\", \"serial\", \"parallel\"])\n", + "plt.legend()\n", + "\n", + "# function to show the plot\n", + "plt.show()" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "d66334a9", + "metadata": {}, + "source": [ + "We can see the `actual` line is much closer to the `parallel` line than the `serial` line, indicating we are running most of the LLMs in parallel.\n", + "\n", + "### 3.2 - Event Driven Pipeline: Creating a Microservice\n", + "\n", + "In a true production environment, the CVE scans would be triggered by some other event, such as a new container being uploaded into a registry or a new project being created. In this section, we will show how to create a microservice that can be triggered by an event and run the pipeline we built in the previous sections.\n", + "\n", + "Previously, when our pipeline was started, it would read all inputs from a DataFrame and run the pipeline for each input. Once the pipeline was done processing the DataFrame, it would shut down. To run the pipeline as a microservice, we need to modify the pipeline to run continuously and listen for new inputs on an HTTP endpoint.\n", + "\n", + "Fortunately, in Morpheus this is as easy as changing out the type of source that is used in the pipeline. The code below is identical to the previous pipeline except we have changed the source from `InMemorySourceStage` to `HttpServerSourceStage`. The `HttpServerSourceStage` class listens for new inputs on an HTTP endpoint and passes them to the next stage in the pipeline. It pulls the inputs from the request body and passes them to the pipeline to be processed.\n", + "\n", + "Additionally, right after the `HttpServerSourceStage` we have added a simple custom stage to the pipeline `print_payload`. This custom stage simply prints the payload that was passed to the pipeline. This is useful for debugging and logging exactly when the pipeline was triggered since the results may take time to process and be shown to the console.\n" + ] + }, + { + "cell_type": "code", + "id": "ca8d4182", + "metadata": { + "tags": [] + }, + "source": [ + "# Code for creating a microservice\n", + "from cyber_dev_day.pipeline_utils import build_cve_llm_engine\n", + "\n", + "from morpheus.messages import ControlMessage\n", + "from morpheus.messages import MessageMeta\n", + "from morpheus.pipeline.linear_pipeline import LinearPipeline\n", + "from morpheus.pipeline.stage_decorator import stage\n", + "from morpheus.stages.input.http_server_source_stage import HttpServerSourceStage\n", + "from morpheus.stages.llm.llm_engine_stage import LLMEngineStage\n", + "from morpheus.stages.output.in_memory_sink_stage import InMemorySinkStage\n", + "from morpheus.stages.preprocess.deserialize_stage import DeserializeStage\n", + "from morpheus.utils.concat_df import concat_dataframes\n", + "from morpheus.utils.http_utils import HTTPMethod\n", + "\n", + "\n", + "async def run_cve_pipeline_microservice(p_config: Config, e_config: EngineConfig):\n", + "\n", + " completion_task = {\"task_type\": \"completion\", \"task_dict\": {\"input_keys\": [\"cve_info\"], }}\n", + "\n", + " pipe = LinearPipeline(p_config)\n", + "\n", + " # Use an HTTP source to listen for requests. The expected payload is:\n", + " # [{\"cve_info\": },\n", + " # {\"cve_info\": },]\n", + " pipe.set_source(\n", + " HttpServerSourceStage(p_config, bind_address=\"0.0.0.0\", port=26302, endpoint=\"/scan\", method=HTTPMethod.POST))\n", + "\n", + " # To see when our pipeline has been triggered, add a simple logging stage to print the payload\n", + " @stage\n", + " def print_payload(payload: MessageMeta) -> MessageMeta:\n", + " serialized_str = payload.df.to_json(orient=\"records\", lines=True)\n", + "\n", + " logger.info(\"======= Got Request =======\\n%s\\n===========================\", serialized_str)\n", + "\n", + " return payload\n", + "\n", + " pipe.add_stage(print_payload(config=p_config))\n", + "\n", + " # The remainder of the pipeline is identical to the previous example\n", + " pipe.add_stage(\n", + " DeserializeStage(p_config, message_type=ControlMessage, task_type=\"llm_engine\", task_payload=completion_task))\n", + "\n", + " pipe.add_stage(LLMEngineStage(p_config, engine=build_cve_llm_engine(e_config)))\n", + "\n", + " sink = pipe.add_stage(InMemorySinkStage(p_config))\n", + "\n", + " await pipe.run_async()\n", + "\n", + " messages = sink.get_messages()\n", + " responses = concat_dataframes(messages)\n", + "\n", + " logger.info(\"Received %s responses:\\n%s\", len(messages), responses[\"response\"])" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "ababebfe", + "metadata": {}, + "source": [ + "Finally, we can start our microservice by running the pipeline as we have in the past. While the pipeline is running, move on to the next section to see how to trigger the pipeline with an HTTP request.\n", + "\n", + "
\n", + "Note: When executed, the following cell will run indefinitely. You will need to interrupt the kernel to stop it. \n", + "
\n" + ] + }, + { + "cell_type": "code", + "id": "f4f87ac9", + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + }, + "tags": [] + }, + "source": [ + "await run_cve_pipeline_microservice(pipeline_config, engine_config)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "ccb51d69", + "metadata": {}, + "source": [ + "#### 3.2.1 - Triggering the Microservice\n", + "\n", + "To trigger the microservice, we will use a CURL request to send a request to the microservice. Since the notebook cannot run commands while the microservice is running, we need to open up a new terminal to send the request. To do that, follow the steps below:\n", + "\n", + "1. In Jupyter Lab, press Ctrl + Shift + L (Shift + ⌘ + L on Mac) to open a new Launcher tab\n", + "2. In the Launcher tab, click on the Terminal icon to open a new terminal\n", + "3. In the terminal, run the following command to send a request to the microservice:\n", + "\n", + "```bash\n", + "curl --request POST \\\n", + " --url http://localhost:26302/scan \\\n", + " --header 'Content-Type: application/json' \\\n", + " --data '[{\n", + " \"cve_info\" : \"An issue was discovered in the Linux kernel through 6.0.9. drivers/media/dvb-core/dvbdev.c has a use-after-free, related to dvb_register_device dynamically allocating fops.\"\n", + " }]'\n", + "```\n", + "\n", + "4. Once the request is sent, the microservice will process the request and return the results in the terminal\n", + " 1. To see the results, switch back to the Notebook tab. You should see that the microservice received your request and started processing it.\n", + " ```\n", + " I20240308 16:00:56.422039 3010283 http_server.cpp:129] Received request: POST : /scan\n", + " ```\n", + " 2. It helps to have the terminal and the notebook side by side so you can see the results in the terminal as they come in. To do this, click on the terminal tab and drag it to the right side of the screen. You should then be able to see the terminal and the notebook side by side similar to the image below:\n", + " ![Terminal and Notebook Side by Side](./images/side_by_side.png)\n", + "5. To stop the microservice, interrupt the kernel by pressing the stop button in the toolbar\n" + ] + }, + { + "cell_type": "markdown", + "id": "65113327", + "metadata": {}, + "source": [ + "## 4 - Conclusion\n", + "\n", + "Throughout this notebook, we explored how GenAI and LLMs can take the transformative role in cybersecurity through automating the CVE analysis workflow. Here are the key learnings and takeaways:\n", + "\n", + "### Generative AI and Cybersecurity\n", + "- **The Role of GenAI and LLMs in Cybersecurity**: Learned about the transformative impact of GenAI and LLMs in cybersecurity, particularly in automating and improving threat detection, analysis, and response. These technologies are crucial for mitigating the manual and time-consuming aspects of cybersecurity tasks.\n", + "\n", + "### CVE Impact Analysis\n", + "- **Challenges in CVE impact analysis**: Challenges include the intensive effort required for gathering information, the complexity of making informed decisions, and the fact that the risk posed by vulnerabilities can vary greatly depending on the specific environment in which they are found.\n", + "- **Event-Driven LLM Agent Pipeline**: Learned about the concept and implementation of an event-driven LLM agent pipeline as a solution to streamline the CVE analysis process. \n", + "\n", + "### Hands-On with LLMs \n", + "- **LLM Inferencing Through NVIDIA Inference Microservices (NIM)**: Interacted with LLMs through NIM and the `nemollm` Python client library, leveraging the cloud-native framework to simplify the process of making LLM inference requests.\n", + "- **Refining Model Outputs with Prompt Engineering**: Gained insights into various prompting techniques, including persona-based prompting, prompt templating, and both one-shot and few-shot learning methods.\n", + "- **Evaluating Model Performance**: Explored strategies for assessing model performance, such as conducting format checks, undergoing manual expert reviews, and creating benchmark datasets.\n", + " \n", + "### Utilization of Retrieval-Augmented Generation (RAG)\n", + "- **RAG Functionality**: Understood how RAG can augment LLM responses by incorporating external knowledge, thus enhancing the accuracy and context-relevance of the outputs for cybersecurity applications.\n", + "- **Building RAG Pipelines with Morpheus**: Learned to build RAG pipelines using NVIDIA Morpheus, focusing on its application in constructing high-performance AI-driven cybersecurity workflows.\n", + "\n", + "### Prototyping to Production\n", + "- **Fine-Tuning for Task-Specific Improvements**: Understood the importance of fine-tuning LLMs on specific tasks to overcome limitations and improve output quality.\n", + "- **Scaling and Parallelization**: Learned about Morpheus’ ability to execute multiple LLM inquiries in parallel, significantly reducing the overall runtime of LLM pipelines.\n", + "- **Event-Driven Microservice Creation**: Explored the creation of a microservice that responds to real-world events, enabling the automated execution of the CVE analysis pipeline in response to triggers such as container updates.\n", + "\n", + "The tutorial demonstrates how to utilize **NIM** and **NVIDIA Morpheus** to develop an LLM-powered agent that assists security analysts with CVE impact analysis. It provides practical insights into refining model outputs, integrating diverse technologies into workflows, and deploying scalable, event-driven solutions for real-world applications. This tutorial serves as a solid starting point for anyone interested in leveraging LLMs to address real-world challenges in cybersecurity and beyond.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/experimental/event-driven-rag-cve-analysis/notebooks/images/multiple_cve_parallel.jpg b/experimental/event-driven-rag-cve-analysis/notebooks/images/multiple_cve_parallel.jpg new file mode 100644 index 000000000..ff8a23266 Binary files /dev/null and b/experimental/event-driven-rag-cve-analysis/notebooks/images/multiple_cve_parallel.jpg differ diff --git a/experimental/event-driven-rag-cve-analysis/notebooks/images/multiple_cve_serial.jpg b/experimental/event-driven-rag-cve-analysis/notebooks/images/multiple_cve_serial.jpg new file mode 100644 index 000000000..e10aaa259 Binary files /dev/null and b/experimental/event-driven-rag-cve-analysis/notebooks/images/multiple_cve_serial.jpg differ diff --git a/experimental/event-driven-rag-cve-analysis/notebooks/images/side_by_side.png b/experimental/event-driven-rag-cve-analysis/notebooks/images/side_by_side.png new file mode 100644 index 000000000..50719c6be Binary files /dev/null and b/experimental/event-driven-rag-cve-analysis/notebooks/images/side_by_side.png differ diff --git a/experimental/event-driven-rag-cve-analysis/notebooks/images/single_cve_parallel.jpg b/experimental/event-driven-rag-cve-analysis/notebooks/images/single_cve_parallel.jpg new file mode 100644 index 000000000..9a050b84a Binary files /dev/null and b/experimental/event-driven-rag-cve-analysis/notebooks/images/single_cve_parallel.jpg differ diff --git a/experimental/event-driven-rag-cve-analysis/notebooks/images/single_cve_serial.jpg b/experimental/event-driven-rag-cve-analysis/notebooks/images/single_cve_serial.jpg new file mode 100644 index 000000000..64fa60e24 Binary files /dev/null and b/experimental/event-driven-rag-cve-analysis/notebooks/images/single_cve_serial.jpg differ diff --git a/experimental/event-driven-rag-cve-analysis/requirements.yaml b/experimental/event-driven-rag-cve-analysis/requirements.yaml new file mode 100644 index 000000000..22d002942 --- /dev/null +++ b/experimental/event-driven-rag-cve-analysis/requirements.yaml @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +channels: + - conda-forge + - huggingface + - pytorch +dependencies: + - aiohttp-client-cache=0.11 + - aiohttp=3.9 + - beautifulsoup4=4.12 + # - faiss-gpu=1.7 # Uncomment this when the package supports CUDA 12. See: https://github.com/conda-forge/faiss-split-feedstock/pull/72 + - faiss=1.7 + - openai=1.13 + - pytorch=*=*cuda* + - sentence-transformers>=2.0.0,<3.0.0 + - tiktoken>=0.3.2,<0.6.0 + - transformers + + ####### Pip Transitive Dependencies (keep sorted!) ####### + # These are dependencies that are available on conda, but are required by the pip packages listed below. Its much + # better to install them with conda than pip to allow for better dependency resolution. + - pydantic=2.6 + + ####### Pip Dependencies (keep sorted!) ####### + - pip + - pip: + - google-search-results==2.4 + - langchain-nvidia-ai-endpoints==0.0.3 + - langchain==0.1.9 + - nemollm==0.3.5 + - pydpkg==1.9.2 diff --git a/experimental/fm-asr-streaming-rag/README.md b/experimental/fm-asr-streaming-rag/README.md index 7a03b6658..7dd4750a4 100644 --- a/experimental/fm-asr-streaming-rag/README.md +++ b/experimental/fm-asr-streaming-rag/README.md @@ -1,67 +1,94 @@ # Streaming FM Radio RAG This repository enables live processing of FM baseband I/Q samples, automatic speech recognition (ASR) of the resulting audio, and LLM interaction with the transcribed audio. +The FM-ASR pipeline is setup to receive I/Q samples over UDP. The Holoscan-based SDR pipeline expects to receive UDP packets containing baseband I/Q data. Signal processing is done to turn that data into PCM audio, which is sent to a Riva server over gRPC for ASR. The detected transcripts are received back by the Holoscan application and are sent to the chain server via REST API. The chain server then uses the embedding service to store embeddings of the transcript in a Milvus database. That data is then retrieved and used to respond to user queries. + If you don't have an SDR capable of recieving FM, that's ok. Code in the `file-replay` container will read in `.wav` audio files, do signal processing to FM-modulate them, and send the data as UDP packets. From the perspective of the pipeline, this file replay data looks equivalent to data streamed in from an FM source. ![FM chatbot](docs/imgs/chatbot.jpg) -## Tools -- [NVIDIA Holoscan SDK](https://developer.nvidia.com/holoscan-sdk) - UDP data ingest and signal processing -- [NVIDIA Riva](https://www.nvidia.com/en-us/ai-data-science/products/riva/) - ASR -- [NVIDIA AI Foundation Endpoint](https://www.nvidia.com/en-us/ai-data-science/foundation-models/) - Optimized LLM inference running on the cloud -- [NVIDIA NIM](https://developer.nvidia.com/docs/nemo-microservices/inference/overview.html) - Convert Hugging Face or Nemo checkpoint to [TRT-LLM](https://github.com/NVIDIA/TensorRT-LLM) and deploy locally with [Triton Inference Server](https://developer.nvidia.com/triton-inference-server) -- [Docker](https://docker.com) - Tested with versions >=25.0.0 +## Components +### Folder organization +*Note: `[optional]` denotes optional components that are disabled by default. If enabled services will be deployed locally, otherwise, endpoints from NVIDIA's API catalog at https://build.nvidia.com/explore/discover will be used.* + +- `chain-server`: Implementation of LangChain connectors to LLM inference, text embedding to database, retrieval and re-ranking of database documents, and interaction with user queries / intent detection. + +- `deploy`: Docker compose files, parameterization, and scripts to deploy application. `compose.env` holds all the environment variables used for deployment. + +- `file-replay`: Enables mimicking RF data with audio file. Reads in a WAV audio file, converts the audio data to baseband I/Q data, and sends the I/Q samples over UDP to the Holoscan SDR pipeline. + +- `frontend`: Gradio-based UI that displays chat interface, LLM parameters, and a live transcription of FM audio data. + +- `nemo-retriever [optional]`: Holds the models and volumes used for the optional [NeMo Retriever Microservice](https://developer.nvidia.com/nemo-microservices) used for deploying embedding service, storage, retrieval, and reranking services. Enabled when `USE_NEMO_RETRIEVER="true"`. + +- `nim [optional]`: Holds configuration and Dockerfile for deploying a NIM LLM locally. Currently configured to run Mistral 7B Instruct v0.2 on an RTX A6000. + +- `sdr-holoscan`: Using the Holoscan SDK, implements data ingest, GPU-accelerated RF signal processing, communication with the Riva server, and export of transcripts to the chain server. + +### Architecture with NeMo Retriever Microservice +![Block Diagram](docs/imgs/architecture-retriever.jpg) + +### Architecture with Standalone Milvus Database and API Endpoints for Embedding / Reranking +![Block Diagram](docs/imgs/architecture-cloud.jpg) + +### Data Source +The SDR application expects to receive UDP packets containing baseband I/Q data that match the address / packet size outlined in `sdr-holoscan/params.yml`. Any data source sending UDP to the specified address / port will be processed by the application. + +This setup has been tested with a [RTL-SDR Blog V.3](https://www.rtl-sdr.com.rtl-sdr-blog-v-3-dongles-user-guide/) SDR in conjunction with a [GNU Radio](https://www.gnuradio.org/) application. A sample companion file is included in [docs/samples/sample_fm_radio.grc](docs/samples/sample_fm_radio.grc). + +Alternatively, WAV audio files can be used to spoof FM data. The `file-replay` container reads the file specified by `REPLAY_FILE`, does FM modulation of the audio data, and transmits the data via UDP. + +### FM-ASR Streaming +The [NVIDIA Holoscan SDK](https://developer.nvidia.com/holoscan-sdk) is used for data ingest and GPU-accelerated signal processing, while [NVIDIA Riva](https://www.nvidia.com/en-us/ai-data-science/products/riva/) is used for automatic speech recognition (ASR). + +### Embedding & Retrieval +Two options are provided for embedding & retrieval which are determined at deploy-time - using the locally deployed NeMo Retriever Microservice, or using a standalone Milvus DB with NVIDIA's Embedding & Reranking API. + +To use the NeMo Retriever Microservice, you must be in the EA program and have access to the container, at which point it can be enabled by setting `USE_NEMO_RETRIEVER="true"`. + +Alternatively, a standalone Milvus DB is stood up. Embeddings are provided by [embed-qa-4](https://build.nvidia.com/nvidia/embed-qa-4), retrieval is done with semantic similarity, and reranking is done on the retrieved documents with [reank-qa-mistral-4b](https://build.nvidia.com/nvidia/rerank-qa-mistral-4b). + +### LLM Inference +Similarly, there are two options for LLM inference - a locally deployed NIM or using the NVIDIA API endpoints. These can both be used while the workflow is running, there is a dropdown in the UI that allows the user to specify which model is being used and can reference either models hosted by NVIDIA or a NIM model hosted locally. ## Hardware and Access Requirements - NVIDIA GPU (or GPUs) capable of running at minimum a Riva ASR server and Holoscan signal processing. This setup has been tested with an [RTX A6000](https://www.nvidia.com/en-us/design-visualization/rtx-a6000/), which handles that workload easily. Pushes the A6000's capability when running LLM inference on the same GPU; a dedicated GPU for inference is recommended when deploying locally. -- A [NVIDIA AI Foundation Endpoint](https://www.nvidia.com/en-us/ai-data-science/foundation-models/) key. Uses [LangChain implementation](https://python.langchain.com/docs/integrations/chat/nvidia_ai_endpoints) for LLM inference. Put your key in `NVIDIA_API_KEY` in `deploy/compose.env`. -- NVIDIA NIM is in early access and container is not available for developers not in EA program. +- A [NVIDIA API Catalog](https://build.nvidia.com/explore/discover?signin=true) key and credits for service usage. Uses [LangChain implementation](https://python.langchain.com/docs/integrations/chat/nvidia_ai_endpoints) for LLM inference. Put your key in `NVIDIA_API_KEY` in `deploy/compose.env`. +- NVIDIA's NeMo Retriever & NIM access are in early access and containers are not available for developers not in EA program. - Access to the [NGC catalog](https://catalog.ngc.nvidia.com/). ## Requirements for running live FM - An SDR and antenna for downconversion and A2D conversion. Tested with [RTL-SDR Blog V.3](https://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/). - [GNU Radio](https://www.gnuradio.org/) or similar software that can deliver baseband I/Q samples over UDP. See a sample companion file [sample_fm_radio.grc](docs/samples/sample_fm_radio.grc). - -## Future Work -- GNU Radio container for users with an SDR +- The SDR should be sending UDP packets that match the address / packet size outlined in `sdr-holoscan/params.yml`. ## Setup ### Riva ASR -NVIDIA Riva is required to perform the automated transcriptions. You will need to install and configure the [NGC-CLI](https://ngc.nvidia.com/setup/installers/cli) tool, if you have not done so already, to obtain the Riva container and API. The Riva installation steps may be found at this link: [Riva-Install](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). Note that Riva performs a TensorRT build during setup and requires access to the targeted GPU. - -Container-based development and deployment is supported. See our sample [sample_riva_config.sh](docs/samples/sample_riva_config.sh) file for an example of how to configure Riva. +NVIDIA Riva is required to perform the automated transcriptions. You will need to install and configure the [NGC-CLI](https://ngc.nvidia.com/setup/installers/cli) tool, if you have not done so already, to obtain the Riva container and API. The Riva installation steps may be found at this link: [Riva-Install](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/quick-start-guide.html). -### Replay -Move a `.wav` file into `file-replay/files`, set the `REPLAY_FILE` to the file name, relative to the `file-replay/files` directory. So `file-replay/files/my-audio.wav` should be `my-audio.wav`. +Note that Riva performs a TensorRT build during setup and requires access to the targeted GPU. Container-based development and deployment is supported. See our sample [sample_riva_config.sh](docs/samples/sample_riva_config.sh) file for an example of how to configure Riva. ### Containers -The project uses Docker Compose to easily build and deploy containers. Environment variables needed to run are in `deploy/compose.env`. - -```bash -source deploy/compose.env -docker compose -f deploy/docker-compose.yml up --build -``` +The project uses Docker Compose to easily build and deploy containers. You must have a supported set of drivers (tested at `545.23.08`) which can be obtained by installing the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads). Additionally, the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) is required to enable GPU usage in Docker containers. Environment variables needed to run are in `deploy/compose.env`. -Alternatively, use `deploy/scripts/run.sh`. +### API Access +Create an account at [NVIDIA API Catalog](https://build.nvidia.com/explore/discover?signin=true) for access to the APIs to call LLM inference, embedding, and reranking models. -### GPUs -The GPU or GPUs used for each container can be specified in `compose.env`. By default all containers have access to 'all' GPUs. +### File Replay +Move a `.wav` file into `file-replay/files`, set the `REPLAY_FILE` to the file name, relative to the `file-replay/files` directory. So, `/path/to/project/file-replay/files/my-audio.wav` should just be `my-audio.wav`. -## NVIDIA NIM -This repository also provides the tools and frameworks for using NVIDIA NIM to build and deploy TensorRT-LLM models on-prem. [Documentation for NVIDIA NIM](https://developer.nvidia.com/docs/nemo-microservices/inference/overview.html). +### Building NVIDIA NIM model from Hugging Face checkpoint +This repository also provides the tools and frameworks for using NVIDIA NIM to build and deploy [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM) models on-prem. [Documentation for NVIDIA NIM](https://developer.nvidia.com/docs/nemo-microservices/inference/overview.html). -### Running without NIM -Currently NVIDIA NIM is in early access and you must have access to pull the container in `nim/Dockerfile`. If you don't have EA, or only want to run on the cloud, just deploy the Docker compose project without the `nim`. You can do this by: -1) Commenting out the `nim` block in the compose file -2) Use the helper script in `nim/deploy/scripts/run-cloud-only.sh` -3) Simply calling compose with all other containers: `docker compose -f docker-compose.yml up --build sdr frontend server replay`. - -### Building TRT-LLM from Hugging Face checkpoint NVIDIA NIM uses the `model_repo_generator` command to build a TRT-LLM engine from a Hugging Face checkpoint. Use the helper script `deploy/scripts/nim-model-build.sh` to build the engine. This engine will be deployed with the inference microservice command called in the main compose file (`nemollm_inference_ms`). A sample configuration file for Mistral 7B v0.2 is included in `nim/configs`. Simply drop your own config in the folder, set appropriate environment variables and build using the playbook above. -## Intent Detection and Planning +## Running +Start the Riva server. Once initialized, start project with helper script `./deploy/scripts/run.sh`. This script sources `./deploy/compose.env` to read environment variables, then deploys containers based on configuration. Use helper script `./deploy/scripts/stop.sh` to bring down all containers. + +## LLM Features & Description +### Intent Detection and Planning By default, the Q&A pipeline is designed to infer some basic intent types from the user query, which affects how information is retrieved. [Pydantic](https://docs.pydantic.dev/latest/) is used under the hood to handle all agent-style planning and action decisions. The 3 types of intent are: 1. Question or comment about a specific topic – “Who do the Boston Bruins play tonight?” 2. Summarization of recent entries – “What are the main stories from the past hour?” @@ -77,11 +104,5 @@ Decision tree for detection and retrieval is shown below: ![Intent tree](docs/imgs/intent-tree.jpg) -## Recusive summarization -As a feature to test capability with edge deployments using smaller models with reduced KV-cache and smaller context windows, this code is enabled to reduce context window via recursive summarization. When enabled, if the number of entries retrieved exceeds the max entries parameter, the context window is reduced via summarization. For each block of `max_entries` entries, the LLM reduces the context by summarizing it, returns the result to the context pool, and re-chunks the summarized result. - -## Block Diagram Overview -### File replay -![Block overview with file replay source](docs/imgs/high-level-replay-overview.jpg) -### Live FM -![Block overview with FM source](docs/imgs/high-level-overview.jpg) \ No newline at end of file +### Recusive summarization +As a feature to test capability with edge deployments using smaller models with reduced KV-cache and smaller context windows, recursive summarization is used to reduce the number of tokens used in the prompt. When enabled, if the number of retrieved vector database entries exceeds the max entries parameter, the total retreived tokens are reduced to a managable amount by reducing them via summarization. For each block of `max_entries` entries, the LLM summarizes the entries, returns the summarized result to the context pool, and re-chunks the summarized result. This continues until the number of tokens used for context fits in the number of entries corresponding to `max_entries`. \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/chain-server/accumulator.py b/experimental/fm-asr-streaming-rag/chain-server/accumulator.py new file mode 100644 index 000000000..c5f2cb1de --- /dev/null +++ b/experimental/fm-asr-streaming-rag/chain-server/accumulator.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from common import get_logger +from database import TimestampDatabase +from langchain.text_splitter import RecursiveCharacterTextSplitter + +logger = get_logger(__name__) + +#todo: Multi-thread to handle multiple concurrent streams +#todo: Add time-triggered embedding (i.e. embed after N seconds if no updates) +class TextAccumulator: + def __init__(self, db_interface, chunk_size=1024, chunk_overlap=200): + self.splitter = RecursiveCharacterTextSplitter( + chunk_size=chunk_size, + chunk_overlap=chunk_overlap, + length_function=len + ) + self.accumulators = {} + self.timestamp_db = TimestampDatabase() + self.db_interface = db_interface + + def update(self, source_id, text): + """ Update this source ID's accumulator and embed if necessary + """ + if source_id not in self.accumulators: + self.accumulators[source_id] = "" + + # Add new text, then chunk using text splitter. If chunking results in + # more than 1 document, embed the full-sized chunks. + docs = self.splitter.split_text(f"{self.accumulators[source_id]} {text}") + self.accumulators[source_id], new_docs = docs[-1], docs[:-1] + self.timestamp_db.insert_docs(new_docs, source_id) + self.db_interface.add_docs(new_docs, source_id) + + return {"status": f"Added {len(new_docs)} entries"} \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/chain-server/chains.py b/experimental/fm-asr-streaming-rag/chain-server/chains.py index 79f6097ad..3bb3a5430 100644 --- a/experimental/fm-asr-streaming-rag/chain-server/chains.py +++ b/experimental/fm-asr-streaming-rag/chain-server/chains.py @@ -13,31 +13,35 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import logging - +from typing import Union from copy import copy from datetime import datetime, timedelta from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from langchain.docstore.document import Document -from database import VectorStoreInterface -from common import LLMConfig, TimeResponse, UserIntent -from utils import get_llm, classify, doc_tstamp +from accumulator import TextAccumulator +from retriever import NemoRetrieverInterface, NvidiaApiInterface +from common import get_logger, LLMConfig, TimeResponse, UserIntent +from utils import get_llm, classify from prompts import RAG_PROMPT, INTENT_PROMPT, RECENCY_PROMPT, SUMMARIZATION_PROMPT -LOG_LEVEL = logging.getLevelName(os.environ.get('CHAIN_LOG_LEVEL', 'WARN').upper()) -logger = logging.getLogger(__name__) -logger.setLevel(LOG_LEVEL) +logger = get_logger(__name__) # Maximum number of times to attempt recursive summarization (if enabled) MAX_SUMMARIZATION_ATTEMPTS = 3 class RagChain: - def __init__(self, config: LLMConfig, db: VectorStoreInterface): + def __init__( + self, + config: LLMConfig, + text_accumulator: TextAccumulator, + retv_interface: Union[NemoRetrieverInterface, NvidiaApiInterface] + ): self.config = config - self.db = db + self.text_accumulator = text_accumulator + self.timestamp_db = text_accumulator.timestamp_db + self.retv_interface = retv_interface self.llm = get_llm(config) self.rag_prompt = ChatPromptTemplate.from_messages([ ("system", RAG_PROMPT), @@ -76,7 +80,9 @@ def answer(self): UserIntent ) - if intent.intentType in ['RecentSummary', 'TimeWindow']: + if intent is None or intent.intentType == 'Unknown': + logger.warning('Unknown user intent, falling back to basic RAG') + elif intent.intentType in ['RecentSummary', 'TimeWindow']: try: # Determine the time units user is asking about recency = classify( @@ -101,32 +107,28 @@ def answer(self): intent.intentType = 'SpecificTopic' # Do basic RAG with semantic similarity retrieval - if intent is None or intent.intentType != 'SpecificTopic': - logger.warning('Unknown user intent, falling back to basic RAG') yield from self.answer_by_relevence() return def answer_by_relevence(self): # Retrieve - docs = self.db.search( + docs = self.retv_interface.search( self.config.question, - max_entries=self.config.max_docs, - score_threshold=self.config.threshold + max_entries=self.config.max_docs ) - yield f"*Returned {len(docs)} related entries*\n" # Output if not len(docs): - yield "*Try to lower the retrieval threshold or be more specific*" + yield "*Found no documents related to the query*" else: - yield "\n" + yield f"*Returned {len(docs)} related entries*\n\n" yield from self.generate(docs) def answer_by_recent(self, recency: TimeResponse): # Retrieve seconds = recency.to_seconds() tstamp = datetime.now() - timedelta(seconds=seconds) - docs = self.db.recent(tstamp) + docs = self.timestamp_db.recent(tstamp) yield f"*Found {len(docs)} entries from the last {seconds:.0f}s*\n" # Handle case when we get too many docs @@ -143,7 +145,7 @@ def answer_by_recent(self, recency: TimeResponse): else: # Just throw some away docs = docs[-self.config.max_docs:] - oldest = doc_tstamp(docs[0]).second + oldest = docs[0].metadata['tstamp'].second yield f"*Reduced to last {len(docs)} entries, oldest is from {oldest}s ago*\n" # Output @@ -155,7 +157,7 @@ def answer_by_past(self, recency: TimeResponse, window=90): # Retrieve seconds = recency.to_seconds() tstamp = datetime.now() - timedelta(seconds=seconds) - docs = self.db.past(tstamp, window=window) + docs = self.timestamp_db.past(tstamp, window=window) yield f"*Found {len(docs)} entries from {seconds:.0f}s ago (+/- {window}s)*\n" # Handle case when we get too many docs @@ -171,9 +173,9 @@ def answer_by_past(self, recency: TimeResponse, window=90): docs = docs[-self.config.max_docs:] else: # Just throw some away - sorted_docs = sorted(docs, key=lambda doc: abs(doc_tstamp(doc) - tstamp)) + sorted_docs = sorted(docs, key=lambda doc: abs(doc.metadata['tstamp'] - tstamp)) docs = sorted_docs[:self.config.max_docs] - dt = abs(doc_tstamp(docs[-1]) - tstamp).seconds + dt = abs(docs[-1].metadata['tstamp'] - tstamp).seconds yield f"*Reduced to last {len(docs)} entries, furthest is {dt}s away*\n" # Output @@ -185,7 +187,7 @@ def summarize(self, docs): """ Given a set of documents, leverage the LLM to reduce context via summarization """ summary_chain = self.get_chat_chain(SUMMARIZATION_PROMPT) - splitter = copy(self.db._text_splitter) + splitter = copy(self.text_accumulator.splitter) splitter._chunk_overlap = 0 # Summarize each chunk of 'max_docs' entries diff --git a/experimental/fm-asr-streaming-rag/chain-server/common.py b/experimental/fm-asr-streaming-rag/chain-server/common.py index b518f9f4e..2ebd68f40 100644 --- a/experimental/fm-asr-streaming-rag/chain-server/common.py +++ b/experimental/fm-asr-streaming-rag/chain-server/common.py @@ -13,43 +13,34 @@ # See the License for the specific language governing permissions and # limitations under the License. +import logging +import requests +import json +import os import numpy as np from datetime import datetime, timedelta from pydantic import BaseModel, Field from typing import Literal from langchain_community.utils.math import cosine_similarity -from langchain_community.embeddings import HuggingFaceEmbeddings + +USE_NEMO_RETRIEVER = os.environ.get('USE_NEMO_RETRIEVER', 'False').lower() in ('true', '1') +NVIDIA_API_KEY = os.environ.get('NVIDIA_API_KEY', 'null') + +def get_logger(name): + LOG_LEVEL = logging.getLevelName(os.environ.get('CHAIN_LOG_LEVEL', 'WARN').upper()) + logger = logging.getLogger(name) + logger.setLevel(LOG_LEVEL) + logger.addHandler(logging.StreamHandler()) + return logger class TextEntry(BaseModel): """ API to store text in database """ transcript: str = Field("Streaming text to store") + source_id: str = Field("Source of text") timestamp: datetime = Field("Timestamp of text") -class SearchDocumentConfig(BaseModel): - """ API to do similarity search on database - """ - content: str = Field("Content to search database for") - max_docs: int = Field("Maximum number of documents to return") - threshold: float = Field("Minimum similarity threshold for docs") - -class RecentDocumentConfig(BaseModel): - """ API to return all documents since timestamp - """ - timestamp: datetime = Field("Timestamp of documents to retrieve up to") - max_docs: int = Field("Maximum number of documents to return") - -class PastDocumentConfig(BaseModel): - """ API to return all documents near timestamp, within window seconds - """ - timestamp: datetime = Field("Timestamp of documents to retrieve near") - max_docs: int = Field("Maximum number of documents to return") - window: int = Field( - description="Window (sec) around which documents from timestamp are returned", - default=90 - ) - class LLMConfig(BaseModel): """ Definition of the LLMConfig API data type """ @@ -60,32 +51,70 @@ class LLMConfig(BaseModel): ) # Model choice name: str = Field("Name of LLM instance to use") - engine: str = Field("Name of engine ['nv-ai-foundation', 'triton-trt-llm']") + engine: str = Field("Name of engine ['nvai-api-endpoint', 'triton-trt-llm']") # Chain parameters use_knowledge_base: bool = Field( description="Whether to use a knowledge base", default=True ) allow_summary: bool = Field("Use recursive summarization to reduce long contexts") temperature: float = Field("Temperature of the LLM response") - threshold: float = Field("Minimum similarity threshold for docs") max_docs: int = Field("Maximum number of documents to return") num_tokens: int = Field("The maximum number of tokens in the response") -""" -For cases where an LLM returns a time unit that doesn't match one of the discrete -options, find the closest with cosine similarity. +def nemo_embedding(text): + """ + Uses the NeMo Embedding MS to convert text to embeddings + - ex: embeddings = nemo_embedding(['Chunk A', 'Chunk B']) + """ + port = os.environ.get('NEMO_EMBEDDING_PORT', 1985) + url = f"http://localhost:{port}/v1/embeddings" + payload = json.dumps({ + "input": text, + "model": "NV-Embed-QA", + "input_type": "query" + }) + headers = {'Content-Type': 'application/json'} + response = requests.request("POST", url, headers=headers, data=payload) + embeddings = [chunk['embedding'] for chunk in response.json()['data']] + return embeddings + +def nvapi_embedding(text): + session = requests.Session() + url = "https://ai.api.nvidia.com/v1/retrieval/nvidia/embeddings" + headers = { + "Authorization": f"Bearer {NVIDIA_API_KEY}", + "Accept": "application/json", + } + payload = { + "input": text, + "input_type": "passage", + "model": "NV-Embed-QA" + } + response = session.post(url, headers=headers, json=payload) + embeddings = [chunk['embedding'] for chunk in response.json()['data']] + return embeddings -Example: 'min' -> 'minutes' -""" -EMBEDDINGS = HuggingFaceEmbeddings() VALID_TIME_UNITS = ["seconds", "minutes", "hours", "days"] -TIME_VECTORS = EMBEDDINGS.embed_documents(VALID_TIME_UNITS) +TIME_VECTORS = None # Lazy loading in 'sanitize_time_unit' +if USE_NEMO_RETRIEVER: + embedding_service = nemo_embedding +else: + embedding_service = nvapi_embedding def sanitize_time_unit(time_unit): + """ + For cases where an LLM returns a time unit that doesn't match one of the + discrete options, find the closest with cosine similarity. + + Example: 'min' -> 'minutes' + """ if time_unit in VALID_TIME_UNITS: return time_unit - unit_embedding = [EMBEDDINGS.embed_query(time_unit)] + if TIME_VECTORS is None: + TIME_VECTORS = embedding_service(VALID_TIME_UNITS) + + unit_embedding = embedding_service([time_unit]) similarity = cosine_similarity(unit_embedding, TIME_VECTORS) return VALID_TIME_UNITS[np.argmax(similarity)] diff --git a/experimental/fm-asr-streaming-rag/chain-server/database.py b/experimental/fm-asr-streaming-rag/chain-server/database.py index 151a5eed5..e8625346c 100644 --- a/experimental/fm-asr-streaming-rag/chain-server/database.py +++ b/experimental/fm-asr-streaming-rag/chain-server/database.py @@ -25,177 +25,70 @@ implementation of what is possible with this sort of streaming workflow. """ -import os -import logging -import faiss +import sqlite3 import datetime import numpy as np -from typing import List +from common import get_logger +from datetime import datetime +from langchain.docstore.document import Document -from langchain_community.embeddings import HuggingFaceInstructEmbeddings -from langchain_community.docstore import InMemoryDocstore -from langchain_community.vectorstores import FAISS -from langchain.text_splitter import RecursiveCharacterTextSplitter +logger = get_logger(__name__) -LOG_LEVEL = logging.getLevelName(os.environ.get('CHAIN_LOG_LEVEL', 'WARN').upper()) -logger = logging.getLogger(__name__) -logger.setLevel(LOG_LEVEL) - -EMBED_INSTRUCT = "Represent the sentence for retrieval: " -EMBED_QUERY = "Represent the question for retrieving supporting texts from the sentence: " - -class TimeIndex: - """ Manages database entry indices, tying the entry index to its timestamp +class TimestampDatabase: + """ Use SQLite database to track time-based entries """ def __init__(self): - self.index: List[int] = [] - self.tstamp: np.ndarray = np.array([], dtype=np.datetime64) - - def size(self): - return len(self.index) - - def get(self, i): - return self.index[i], self.tstamp[i] - - def get_range(self, start=None, stop=None): - return self.index[start:stop], self.tstamp[start:stop] - - def reduce_to(self, start=None, stop=None): - self.index, self.tstamp = self.get_range(start, stop) - - def append(self, new_id, new_tstamp): - self.index.append(new_id) - self.tstamp = np.append(self.tstamp, new_tstamp) - - def time_window(self, tstart=None, tend=None): - if not tstart: - tstart = self.tstamp[0] - if not tend: - tend = self.tstamp[-1] - mask = (self.tstamp >= tstart) & (self.tstamp <= tend) - return [self.index[i] for i in np.where(mask)[0]] - - def next_id(self): - return self.index[-1] + 1 if self.size() > 0 else 0 - -class DatabaseManager: - """ Self-managed FAISS database that ties entries to when they were added - """ - def __init__(self, embedding_model, embedding_dim): - self._timeindex = TimeIndex() - self._db_index = faiss.IndexFlatL2(embedding_dim) - self._db = FAISS( - embedding_model, - self._db_index, - InMemoryDocstore({}), - {} - ) - - def size(self): - return self._timeindex.size() - - def pop_back(self): - if self.size() == 0: - return None - - # Get the last document and delete it - idx, _ = self._timeindex.get(-1) - doc = self._db.docstore._dict[idx] - self._db.delete([self._db.index_to_docstore_id[idx]]) - - # Adjust the indices and timestamps - self._timeindex.reduce_to(stop=-1) - return doc - - def pop_front(self): - if self.size() == 0: - return None - - # Get the document and delete it - idx, _ = self._timeindex.get(0) - doc = self._db.docstore._dict[idx] - self._db.delete([self._db.index_to_docstore_id[idx]]) - - # Adjust the indices and timestamps - self._timeindex.reduce_to(start=1) - return doc - - def push_back(self, entry, tstamp): - # Add the entry to the database - new_id = self._timeindex.next_id() - self._db.add_texts( - [entry], ids=[new_id], metadatas=[{'tstamp': tstamp.strftime("%Y-%m-%d %H:%M:%S")}] + self.conn = sqlite3.connect('timeseries.db', check_same_thread=False) + self.cursor = self.conn.cursor() + + # Create table + self.cursor.execute( + ''' + CREATE TABLE IF NOT EXISTS messages ( + id INTEGER PRIMARY KEY, + text TEXT, + timestamp DATETIME, + source_id TEXT + ) + ''' ) - self._timeindex.append(new_id, tstamp) - - def as_retriever(self, search_kwargs): - return self._db.as_retriever( - search_type='similarity_score_threshold', - search_kwargs=search_kwargs - ) - - def get_by_time(self, tstart=None, tend=None): - if self.size() == 0: - return [] - indices = self._timeindex.time_window(tstart=tstart, tend=tend) - return [self._db.docstore._dict[i] for i in indices] - -class VectorStoreInterface: - """ Manages interfacing with the vector store - """ - def __init__(self, chunk_size=1024, chunk_overlap=200): - self._text_splitter = RecursiveCharacterTextSplitter( - chunk_size=chunk_size, - chunk_overlap=chunk_overlap, - length_function=len + self.conn.commit() + + def insert_docs(self, docs, source_id): + tnow = datetime.now() + self.cursor.executemany( + ''' + INSERT INTO messages (text, timestamp, source_id) VALUES (?, ?, ?) + ''', + [(doc, tnow, source_id) for doc in docs] ) - self._embed_model = HuggingFaceInstructEmbeddings( - embed_instruction=EMBED_INSTRUCT, - query_instruction=EMBED_QUERY + self.conn.commit() + + def reformat(self, doc): + return {'content': doc[1], 'timestamp': doc[2], 'source_id': doc[3]} + + def reformat(self, doc): + return Document( + page_content=doc[1], + metadata={ + 'tstamp': datetime.strptime(doc[2], "%Y-%m-%d %H:%M:%S.%f"), + 'source_id': doc[3] + } ) - embedding_pool = self._embed_model.dict()['client'][1] - self.embedding_dim = embedding_pool.get_config_dict()['word_embedding_dimension'] - self._db_mgr = DatabaseManager(self._embed_model, self.embedding_dim) - - def dbsize(self): - return self._db_mgr.size() - - def store_text(self, text, tstamp): - """ Split text into chunks and store in DB - """ - new_entries = self._text_splitter.split_text(text) - for entry in new_entries: - self._db_mgr.push_back(entry, tstamp) - return { - "status": - f"Added {len(new_entries)} entries. " + - f"Number of total database entries: {self.dbsize()}" - } - - def store_streaming_text(self, text, tstamp): - """ Assume last entry was short, delete it, append it to new text, and re-chunk - """ - prev_doc = self._db_mgr.pop_back() - if prev_doc: - text = f"{prev_doc.page_content} {text}" - return self.store_text(text, tstamp) - - def search(self, query, max_entries=4, score_threshold=0.65): - """ Search DB for similar documents - """ - search_kwargs = {'k': max_entries, 'score_threshold': score_threshold} - retriever = self._db_mgr.as_retriever(search_kwargs) - return [doc for doc in retriever.get_relevant_documents(query)] def recent(self, tstamp): """ Return all entries since tstamp """ - return self._db_mgr.get_by_time(tstart=tstamp) + self.cursor.execute("SELECT * FROM messages WHERE timestamp >= ?", (tstamp,)) + docs = self.cursor.fetchall() + return [self.reformat(doc) for doc in docs] def past(self, tstamp, window=90): """ Return entries within 'window' seconds of tstamp """ tstart = tstamp - datetime.timedelta(seconds=window) tend = tstamp + datetime.timedelta(seconds=window) - return self._db_mgr.get_by_time(tstart=tstart, tend=tend) \ No newline at end of file + self.cursor.execute('SELECT * FROM messages WHERE timestamp BETWEEN ? AND ?', (tstart, tend)) + docs = self.cursor.fetchall() + return [self.reformat(doc) for doc in docs] \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/chain-server/requirements.txt b/experimental/fm-asr-streaming-rag/chain-server/requirements.txt index 29e71b7ea..8d20ffa00 100644 --- a/experimental/fm-asr-streaming-rag/chain-server/requirements.txt +++ b/experimental/fm-asr-streaming-rag/chain-server/requirements.txt @@ -1,23 +1,21 @@ fastapi==0.104.1 uvicorn[standard]==0.24.0 python-multipart==0.0.6 -langchain==0.0.352 unstructured[all-docs]==0.11.2 sentence-transformers==2.2.2 llama-index==0.9.22 -pymilvus==2.3.1 +pymilvus==2.3.5 dataclass-wizard==0.22.2 opencv-python==4.8.0.74 minio==7.2.0 asyncpg==0.29.0 psycopg2-binary==2.9.9 pgvector==0.2.4 -langchain-core==0.1.3 -langchain-nvidia-ai-endpoints==0.0.1 +langchain==0.1.14 +langchain-core==0.1.40 +langchain-nvidia-ai-endpoints==0.0.12 langchain-nvidia-trt==0.0.1rc0 nemollm==0.3.4 opentelemetry-sdk==1.21.0 opentelemetry-api==1.21.0 -opentelemetry-exporter-otlp-proto-grpc==1.21.0 -faiss-cpu==1.7.4 -instructorembedding==1.0.1 \ No newline at end of file +opentelemetry-exporter-otlp-proto-grpc==1.21.0 \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/chain-server/retriever.py b/experimental/fm-asr-streaming-rag/chain-server/retriever.py new file mode 100644 index 000000000..5aa91d387 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/chain-server/retriever.py @@ -0,0 +1,352 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import requests +import json +import time + +from common import get_logger, NVIDIA_API_KEY +from statistics import stdev, mean +from datetime import datetime + +from langchain.docstore.document import Document +from pymilvus import ( + MilvusClient, + MilvusException, + Collection, + connections, + utility, + CollectionSchema, + DataType, + FieldSchema +) + +logger = get_logger(__name__) + +RETRIEVER_URI = os.environ.get('NEMO_RETRIEVER_URI', 'localhost:1984') +MILVUS_URI = os.environ.get('MILVUS_STANDALONE_URI', 'localhost:19530') +DEFAULT_DB_NAME = "FM_Radio_Stream" +EMBEDDING_ENDPOINT = "https://ai.api.nvidia.com/v1/retrieval/nvidia/embeddings" +RERANKING_ENDPOINT = "https://ai.api.nvidia.com/v1/retrieval/nvidia/reranking" + +class NemoRetrieverInterface: + """ Uses NeMo Retriever microservice for embeddings / retrieval + """ + def __init__(self, retriever_uri=RETRIEVER_URI): + self.retriever_uri = retriever_uri + + # Connect to Retreiver Microservice + connected = False + start_time = time.time() + timeout = 300 + wait_sec = 5 + while not connected: + try: + # Initialize collection and get ID + response = requests.post( + f"http://{self.retriever_uri}/v1/collections", + headers={'Content-Type': 'application/json'}, + data=json.dumps({ + 'name': f'{DEFAULT_DB_NAME}_Collection', + 'pipeline': 'ranked_hybrid' + }) + ) + response.raise_for_status() + connected = True + except requests.exceptions.ConnectionError: + # Check for timeout + elapsed_time = time.time() - start_time + if elapsed_time > timeout: + logger.error(f"Timeout: {self.retriever_uri} not open after {elapsed_time} seconds") + raise TimeoutError + + # Wait a short period before trying again + logger.warning(f"Waiting {wait_sec}s for Retriever MS at {self.retriever_uri}") + time.sleep(wait_sec) + except requests.HTTPError as e: + logger.error(f"Error {e} when initializing collection at {self.retriever_uri}") + return + except requests.Timeout: + logger.error(f"Timeout reached when initializing collection at {self.retriever_uri}") + return + + self.collection = response.json()['collection'] + self.collection_url = f"http://{self.retriever_uri}/v1/collections/{self.collection['id']}" + logger.info(f"Initialized collection {self.collection['id']}") + + def _reformat(self, doc): + return Document( + page_content=doc['content'], + metadata={ + 'tstamp': datetime.fromisoformat(doc['metadata']['_indexed_at']), + 'source_id': doc['metadata']['source_id'] + } + ) + + def _drop_outliers(self, docs, min_cv=0.1): + """ Drop any documents that are not relevant enough + """ + if self.collection["pipeline"] == "ranked_hybrid": + # With reranking + scores = [doc['score'] for doc in docs] + low_rank_score = scores[0] - max(stdev(scores), min_cv * abs(mean(scores))) + return list(filter(lambda doc: doc['score'] >= low_rank_score, docs)) + else: + # Without reranking + pass + + def add_docs(self, docs, source_id): + """ Add documents to vector DB + """ + for doc in docs: + self._embed(doc, source_id) + + def _embed(self, doc, source_id): + """ Use the NeMo Retriever Embedding microservice + """ + try: + response = requests.post( + f"{self.collection_url}/documents", + headers={'Content-Type': 'application/json'}, + data=json.dumps([{ + "content": doc, + "format": "txt", + "metadata": {"source_id": source_id} + }]) + ) + response.raise_for_status() + logger.info( + f"Embedded document {response.json()['documents'][0]['id']} " + f"to {self.collection_url} [CODE {response.status_code}]" + ) + except requests.HTTPError as e: + logger.error(f"Error {e} when embedding to {self.collection_url}") + except requests.Timeout: + logger.error(f"Timeout reached when embedding to {self.collection_url}") + + def search(self, query, max_entries=None): + """ Use the NeMo Retriever Embedding microservice + """ + try: + response = requests.post( + f"{self.collection_url}/search", + headers={'Content-Type': 'application/json'}, + data=json.dumps({"query": query}) + ) + response.raise_for_status() + except requests.HTTPError as e: + logger.error(f"Error {e} when embedding to {self.collection_url}") + return None + except requests.Timeout: + logger.error(f"Timeout reached when embedding to {self.collection_url}") + return None + + docs = response.json()["chunks"] + logger.info(f"Retrieved {len(docs)} docs") + if len(docs) == 0: + return [] + + if len(docs) > 1: + docs = self._drop_outliers(docs) + return [self._reformat(doc) for doc in docs[:max_entries]] + +class NvidiaApiInterface: + def __init__(self, milvus_uri=MILVUS_URI, db_name=DEFAULT_DB_NAME): + self._create_collection(milvus_uri, db_name) + self.client = MilvusClient( + collection_name=self.collection_name, + uri=f'http://{milvus_uri}', + vector_field="embedding", + overwrite=False + ) + self.headers = { + "Authorization": f"Bearer {NVIDIA_API_KEY}", + "Accept": "application/json", + } + self.session = requests.Session() + + def _create_collection(self, milvus_uri, db_name): + """ Connect to standalone Milvus & create collection + """ + # Connect to standalone Milvus server + connected = False + start_time = time.time() + timeout = 300 + wait_sec = 5 + while not connected: + try: + connections.connect(uri=f'http://{milvus_uri}') + connected = True + except MilvusException: + # Check for timeout + elapsed_time = time.time() - start_time + if elapsed_time > timeout: + logger.error(f"Timeout: {milvus_uri} not open after {elapsed_time} seconds") + raise TimeoutError + + # Wait a short period before trying again + logger.warning(f"Waiting {wait_sec}s for Milvus at {milvus_uri}") + time.sleep(wait_sec) + + # Drop old collection + self.collection_name = f"{db_name}_Collection" + utility.drop_collection(self.collection_name) + + # Define schema + self.index_params = { + "metric_type": "L2", + "index_type": "IVF_FLAT", + "params": {"nlist": 128, "nprobe": 8,}, + } + reference_id = FieldSchema( + name="reference_id", + dtype=DataType.INT64, + is_primary=True, + auto_id=True + ) + source_id = FieldSchema( + name="source_id", + dtype=DataType.VARCHAR, + default_value="Source ID Unknown", + max_length=4096 + ) + text = FieldSchema( + name="text", + dtype=DataType.VARCHAR, + default_value="Text Unknown", + max_length=4096 + ) + embedding = FieldSchema( + name="embedding", + dtype=DataType.FLOAT_VECTOR, + dim=1024 + ) + self.schema = CollectionSchema( + fields=[reference_id, source_id, text, embedding], + description="FM Radio Stream" + ) + + # Create collection + self.collection = Collection( + name=self.collection_name, + schema=self.schema, + using="default" + ) + self.collection.create_index( + field_name="embedding", + index_params=self.index_params, + index_name="embedding_index" + ) + + def add_docs(self, docs, source_id): + """ Add documents to vector DB + """ + for doc in docs: + # Embed into Milvus database + embedding = self._embed(doc, input_type="passage") + result = self.collection.insert([[source_id], [doc], [embedding]]) + self.collection.load() + logger.info( + f"Embedded document {result.insert_count} to {self.collection_name}" + ) + + def _embed(self, doc, input_type="passage"): + """ Use the NeMo Embedding microservice and store + """ + # Call embedding API endpoint + try: + response = self.session.post( + EMBEDDING_ENDPOINT, + headers=self.headers, + json={ + "input": doc, + "input_type": input_type, + "model": "NV-Embed-QA" + } + ) + response.raise_for_status() + return response.json()['data'][0]['embedding'] + except requests.HTTPError as e: + logger.error(f"Error {e} when embedding with API Endpoint") + except requests.Timeout: + logger.error(f"Timeout reached when embedding with API Endpoint") + + def _rerank_docs(self, docs, query): + """ Use the NeMo Reranking microservice + """ + # Call embedding API endpoint + try: + response = self.session.post( + RERANKING_ENDPOINT, + headers=self.headers, + json={ + "query": {"text": query}, + "model": "nv-rerank-qa-mistral-4b:1", + "passages": [{"text": doc['entity']['text']} for doc in docs] + } + ) + response.raise_for_status() + return response.json()['rankings'] + except requests.HTTPError as e: + logger.error(f"Error {e} when embedding with API Endpoint") + except requests.Timeout: + logger.error(f"Timeout reached when embedding with API Endpoint") + + def _reformat(self, doc): + return Document( + page_content=doc['entity']['text'], + metadata={ + 'tstamp': None, #todo + 'source_id': doc['entity']['source_id'] + } + ) + + def _drop_outliers(self, docs, min_cv=0.1): + """ Drop any documents that are not relevant enough + """ + scores = [doc['logit'] for doc in docs] + low_rank_score = scores[0] - max(stdev(scores), min_cv * abs(mean(scores))) + return list(filter(lambda doc: doc['logit'] >= low_rank_score, docs)) + + def search(self, query, max_entries=None): + # Do similarity search on Milvus DB + search_params = { + "metric_type": "L2", + "index_type": "IVF_FLAT", + "params": { + "radius": 1.0, + "range_filter": 0.0, + }, + } + self.collection.load() + docs = self.client.search( + data=[self._embed(query, input_type="query")], + limit=max_entries, + collection_name=self.collection_name, + search_params=search_params, + output_fields=["reference_id", "source_id", "text"] + )[0] + if len(docs) == 0: + return [] + + # Do reranking + rankings = self._rerank_docs(docs, query) + for (rank, doc) in zip(rankings, docs): + doc['logit'] = rank['logit'] + + if len(docs) > 1: + docs = self._drop_outliers(docs) + return [self._reformat(doc) for doc in docs] \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/chain-server/server.py b/experimental/fm-asr-streaming-rag/chain-server/server.py index b9c8e3ad8..5ac17c823 100644 --- a/experimental/fm-asr-streaming-rag/chain-server/server.py +++ b/experimental/fm-asr-streaming-rag/chain-server/server.py @@ -14,60 +14,58 @@ # limitations under the License. import os -import logging -from database import VectorStoreInterface +from accumulator import TextAccumulator +from retriever import NemoRetrieverInterface, NvidiaApiInterface from chains import RagChain from common import ( + get_logger, TextEntry, - SearchDocumentConfig, - RecentDocumentConfig, - PastDocumentConfig, - LLMConfig + LLMConfig, + USE_NEMO_RETRIEVER ) +from langchain_nvidia_ai_endpoints import ChatNVIDIA + from fastapi import FastAPI, Request from fastapi.responses import JSONResponse, StreamingResponse -LOG_LEVEL = logging.getLevelName(os.environ.get('CHAIN_LOG_LEVEL', 'WARN').upper()) -logger = logging.getLogger(__name__) -logger.setLevel(LOG_LEVEL) +logger = get_logger(__name__) app = FastAPI() -# Create vector database -db = VectorStoreInterface( +# Create retriever and accumulators +if USE_NEMO_RETRIEVER: + db_interface = NemoRetrieverInterface() +else: + db_interface = NvidiaApiInterface() + +text_accumulator = TextAccumulator( + db_interface, chunk_size=int(os.environ.get('DB_CHUNK_SIZE', 256)), chunk_overlap=int(os.environ.get('DB_CHUNK_OVERLAP', 32)) ) +@app.get("/availableNvidiaModels") +async def available_nvidia_models(request: Request) -> JSONResponse: + models = [m.id for m in ChatNVIDIA.get_available_models() if m.model_type == 'chat'] + return JSONResponse({ + "models": models + }) + +@app.get("/serverStatus") +async def server_status(): + return {"is_ready": True} # API for database storage and searching @app.post("/storeStreamingText") async def store_streaming_text(request: Request, data: TextEntry) -> JSONResponse: return JSONResponse( - db.store_streaming_text(data.transcript, tstamp=data.timestamp) + text_accumulator.update(data.source_id, data.transcript) ) -@app.get("/searchDocuments") -async def search_documents(request: Request, data: SearchDocumentConfig) -> JSONResponse: - docs = db.search( - data.content, max_entries=data.max_docs, score_threshold=data.threshold - ) - return JSONResponse([doc.dict() for doc in docs]) - -@app.get("/recentDocuments") -async def recent_documents(request: Request, data: RecentDocumentConfig) -> JSONResponse: - docs = db.recent(data.timestamp, max_entries=data.max_docs) - return JSONResponse([doc.dict() for doc in docs]) - -@app.get("/pastDocuments") -async def past_documents(request: Request, data: PastDocumentConfig) -> JSONResponse: - docs = db.past(data.timestamp, window=data.window, max_entries=data.max_docs) - return JSONResponse([doc.dict() for doc in docs]) - # API for LLM interaction @app.get("/generate") async def generate_answer(request: Request, config: LLMConfig) -> StreamingResponse: - chain = RagChain(config, db) + chain = RagChain(config, text_accumulator, db_interface) return StreamingResponse(chain.answer()) \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/chain-server/utils.py b/experimental/fm-asr-streaming-rag/chain-server/utils.py index 8831d8b42..bf6b897ba 100644 --- a/experimental/fm-asr-streaming-rag/chain-server/utils.py +++ b/experimental/fm-asr-streaming-rag/chain-server/utils.py @@ -14,37 +14,27 @@ # limitations under the License. import os -import logging import json import re -from datetime import datetime from langchain_nvidia_ai_endpoints import ChatNVIDIA -from langchain_community.chat_models import ChatOpenAI from pydantic import BaseModel -from common import LLMConfig +from common import get_logger, LLMConfig -LOG_LEVEL = logging.getLevelName(os.environ.get('CHAIN_LOG_LEVEL', 'WARN').upper()) -logger = logging.getLogger(__name__) -logger.setLevel(LOG_LEVEL) +logger = get_logger(__name__) def get_llm(config: LLMConfig): + client = ChatNVIDIA( + model=config.name, + temperature=config.temperature, + max_tokens=config.num_tokens + ) if config.engine == "triton-trt-llm": - openai_port = os.environ.get('NIM_OPENAI_PORT', 9999) - return ChatOpenAI( - model_name=config.name, - temperature=config.temperature, - max_tokens=config.num_tokens, - openai_api_base=f"http://0.0.0.0:{openai_port}/v1/", - openai_api_key="not needed" - ) - elif config.engine == "nv-ai-foundation": - return ChatNVIDIA( - model=config.name, - temperature=config.temperature, - max_tokens=config.num_tokens - ) + nim_llm_port = os.environ.get('NIM_LLM_PORT', 9999) + return client.mode("nim", base_url=f"http://0.0.0.0:{nim_llm_port}/v1") + elif config.engine == "nvai-api-endpoint": + return client else: raise ValueError(f"Unknown engine {config.engine}") @@ -65,11 +55,9 @@ def classify(question, chain, pydantic_obj: BaseModel): # Neither approach worked, return None logger.error(f"Error parsing output into {pydantic_obj}: '{output}'") result = None + logger.info(f"Result: {result}") return result -def doc_tstamp(doc): - return datetime.strptime(doc.metadata['tstamp'], "%Y-%m-%d %H:%M:%S") - """ These are some functions that try to fix some common mistakes LLMs might make when outputting structured JSON. Rather than immediately giving up, we replace diff --git a/experimental/fm-asr-streaming-rag/deploy/compose.env b/experimental/fm-asr-streaming-rag/deploy/compose.env index 1261ce735..4bdfb2771 100644 --- a/experimental/fm-asr-streaming-rag/deploy/compose.env +++ b/experimental/fm-asr-streaming-rag/deploy/compose.env @@ -3,8 +3,13 @@ # Setup directories export DEPLOY_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 ; pwd -P )" export PROJECT_DIR="${DEPLOY_DIR}/.." +export NEMO_RET_DIR="${PROJECT_DIR}/nemo-retriever" export MODEL_DIR="/path/to/llm/checkpoints/" # where you keep your model checkpoints +# Deployment configuration +export USE_NEMO_RETRIEVER="false" +export DEPLOY_LOCAL_NIM="false" + # Connections export FRONTEND_URI="localhost:6001" export FRONTEND_SERVER_PORT="8090" @@ -21,13 +26,13 @@ export NVIDIA_API_KEY="" export DB_CHUNK_SIZE=1024 export DB_CHUNK_OVERLAP=128 -# NIM settings -# Currently configured to build Mistral 7B (with example config) -export LLM="mistralai/Mistral-7B-Instruct-v0.2" # directory of checkpoint, relative to MODEL_DIR -export MODEL_CHECKPOINT="${MODEL_DIR}/${LLM}" -export NIM_MODEL_PATH="${MODEL_DIR}/nim/${LLM}" +# NIM settings - currently configured to build Mistral 7B (with example config) +export NIM_LLM="mistralai/Mistral-7B-Instruct-v0.2" # directory of checkpoint, relative to MODEL_DIR +export NIM_LLM_DISPLAY="mistral_7b" +export MODEL_CHECKPOINT="${MODEL_DIR}/${NIM_LLM}" +export NIM_MODEL_PATH="${MODEL_DIR}/nim/${NIM_LLM}" export NIM_CONFIG_FILE="${PROJECT_DIR}/nim/configs/mistral-7b.yaml" -export NIM_OPENAI_PORT=9999 +export NIM_LLM_PORT=9999 # File replay settings # If a replay file is provided, the 'file-replay' container will replay a @@ -46,3 +51,11 @@ export REPLAY_FILE="" # WAV file to replay. Should be located in file-replay/fi # export CHAIN_GPU=0 # [optional, default='all'] # export REPLAY_GPU=0 # [optional, default='all'] # export NIM_GPU=0 # [optional, default='all'] +# export EMBED_GPU=0 # [optional, default='all'] +# export RANKING_GPU=0 # [optional, default='all'] + +# For NeMo Retriever +export NEMO_RETRIEVER_URI="localhost:1984" +export NEMO_RETRIEVER_PORT=${NEMO_RETRIEVER_URI##*:} +export NEMO_EMBEDDING_PORT=1985 +export NEMO_RANKING_MODEL="nv-rerank-qa-mistral-4b_v1_A6000" diff --git a/experimental/fm-asr-streaming-rag/deploy/docker-compose-file-replay.yaml b/experimental/fm-asr-streaming-rag/deploy/docker-compose-file-replay.yaml new file mode 100644 index 000000000..6bc2d340f --- /dev/null +++ b/experimental/fm-asr-streaming-rag/deploy/docker-compose-file-replay.yaml @@ -0,0 +1,54 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + replay: + container_name: fm-asr-file-replay + image: fm-asr-file-replay:latest + build: + context: ${PROJECT_DIR?:source compose.env}/file-replay + dockerfile: Dockerfile + + environment: + TZ: ${TIMEZONE:-America/New_York} + + volumes: + - ${PROJECT_DIR}/file-replay/files:/workspace/files + + working_dir: /workspace/ + command: > + python wav_replay.py + --file-name ${REPLAY_FILE} + --dst-ip ${SDR_IP:-"0.0.0.0"} + --dst-port ${SDR_PORT:-5005} + --sample-rate ${SDR_SAMPLE_RATE:-1000000} + --packet-size ${SDR_MAX_PKT_SZ:-1472} + --total-time ${REPLAY_TIME:-0} + + network_mode: host + devices: + - "/dev/bus/usb:/dev/bus/usb" + - "/dev/snd:/dev/snd" + + # Enable GPU usage + runtime: nvidia + shm_size: 8gb + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['${REPLAY_GPU:-0}'] + capabilities: [gpu] \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/deploy/docker-compose.yml b/experimental/fm-asr-streaming-rag/deploy/docker-compose-fm-asr.yaml similarity index 53% rename from experimental/fm-asr-streaming-rag/deploy/docker-compose.yml rename to experimental/fm-asr-streaming-rag/deploy/docker-compose-fm-asr.yaml index 977b24d25..d150d6b5d 100644 --- a/experimental/fm-asr-streaming-rag/deploy/docker-compose.yml +++ b/experimental/fm-asr-streaming-rag/deploy/docker-compose-fm-asr.yaml @@ -13,12 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -version: '3' - services: sdr: - container_name: fm-rag-sdr - image: fm-rag-sdr-holoscan:latest + container_name: fm-asr-sdr-holoscan + image: fm-asr-sdr-holoscan:latest build: context: ${PROJECT_DIR?:source compose.env}/sdr-holoscan dockerfile: Dockerfile @@ -47,12 +45,12 @@ services: reservations: devices: - driver: nvidia - device_ids: ['${SDR_GPU:-all}'] + device_ids: ['${SDR_GPU:-0}'] capabilities: [gpu] frontend: - container_name: fm-rag-frontend - image: fm-rag-frontend:latest + container_name: fm-asr-frontend + image: fm-asr-frontend:latest build: context: ${PROJECT_DIR?:source compose.env}/frontend dockerfile: Dockerfile @@ -65,6 +63,8 @@ services: FRONTEND_URI: ${FRONTEND_URI} APP_SERVERURL: http://localhost APP_SERVERPORT: ${CHAIN_SERVER_PORT} + DEPLOY_LOCAL_NIM: ${DEPLOY_LOCAL_NIM} + NIM_LLM_DISPLAY: ${NIM_LLM_DISPLAY} ports: - "${CHAIN_SERVER_PORT}:${CHAIN_SERVER_PORT}" @@ -77,12 +77,12 @@ services: reservations: devices: - driver: nvidia - device_ids: ['${FRONTEND_GPU:-all}'] + device_ids: ['${FRONTEND_GPU:-0}'] capabilities: [gpu] server: - container_name: fm-rag-chain-server - image: fm-rag-chain-server:latest + container_name: fm-asr-chain-server + image: fm-asr-chain-server:latest build: context: ${PROJECT_DIR?:source compose.env}/chain-server dockerfile: Dockerfile @@ -95,6 +95,10 @@ services: CHAIN_LOG_LEVEL: ${CHAIN_LOG_LEVEL:-WARN} DB_CHUNK_SIZE: ${DB_CHUNK_SIZE:-256} DB_CHUNK_OVERLAP: ${DB_CHUNK_OVERLAP:-32} + NEMO_RETRIEVER_URI: ${NEMO_RETRIEVER_URI} + NIM_LLM_PORT: ${NIM_LLM_PORT} + NEMO_EMBEDDING_PORT: ${NEMO_EMBEDDING_PORT} + USE_NEMO_RETRIEVER: ${USE_NEMO_RETRIEVER} ports: - "8081:8081" @@ -107,82 +111,5 @@ services: reservations: devices: - driver: nvidia - device_ids: ['${CHAIN_GPU:-all}'] - capabilities: [gpu] - - replay: - container_name: fm-rag-file-replay - image: fm-rag-file-replay:latest - build: - context: ${PROJECT_DIR?:source compose.env}/file-replay - dockerfile: Dockerfile - - environment: - TZ: ${TIMEZONE:-America/New_York} - - volumes: - - ${PROJECT_DIR}/file-replay/files:/workspace/files - - working_dir: /workspace/ - command: > - python wav_replay.py - --file-name ${REPLAY_FILE} - --dst-ip ${SDR_IP:-"0.0.0.0"} - --dst-port ${SDR_PORT:-5005} - --sample-rate ${SDR_SAMPLE_RATE:-1000000} - --packet-size ${SDR_MAX_PKT_SZ:-1472} - --total-time ${REPLAY_TIME:-0} - - network_mode: host - devices: - - "/dev/bus/usb:/dev/bus/usb" - - "/dev/snd:/dev/snd" - - # Enable GPU usage - runtime: nvidia - shm_size: 8gb - deploy: - resources: - reservations: - devices: - - driver: nvidia - device_ids: ['${REPLAY_GPU:-all}'] - capabilities: [gpu] - - nim: - container_name: fm-rag-nim - image: nim:latest - build: - context: ${PROJECT_DIR?:source compose.env}/nim - dockerfile: Dockerfile - - volumes: - - ${MODEL_CHECKPOINT}:/huggingface-dir - - ${NIM_MODEL_PATH}:/model-store - - ${NIM_CONFIG_FILE}:/model_config.yaml - - environment: - NIM_OPENAI_PORT: ${NIM_OPENAI_PORT} - - ports: - - "${NIM_OPENAI_PORT}:${NIM_OPENAI_PORT}" - expose: - - "${NIM_OPENAI_PORT}" - - # Start inference server - command: > - nemollm_inference_ms - --model mistral_7b - --openai_port=${NIM_OPENAI_PORT} - --num_gpus=1 - - # Enable GPU usage - runtime: nvidia - shm_size: 8gb - deploy: - resources: - reservations: - devices: - - driver: nvidia - device_ids: ['${NIM_GPU:-all}'] - capabilities: [gpu] \ No newline at end of file + device_ids: ['${CHAIN_GPU:-0}'] + capabilities: [gpu] \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/deploy/docker-compose-milvus-standalone.yaml b/experimental/fm-asr-streaming-rag/deploy/docker-compose-milvus-standalone.yaml new file mode 100644 index 000000000..4664fda99 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/deploy/docker-compose-milvus-standalone.yaml @@ -0,0 +1,82 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + etcd: + image: quay.io/coreos/etcd:v3.5.11 + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + - ETCD_SNAPSHOT_COUNT=50000 + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/etcd:/etcd:Z + command: + etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls + http://0.0.0.0:2379 --data-dir /etcd + healthcheck: + test: ["CMD", "etcdctl", "endpoint", "health"] + interval: 30s + timeout: 20s + retries: 3 + + minio: + image: minio/minio:RELEASE.2023-03-20T20-16-18Z + environment: + MINIO_ACCESS_KEY: minioadmin + MINIO_SECRET_KEY: minioadmin + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/minio:/minio_data:Z + command: minio server /minio_data --console-address ":9001" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + milvus: + image: milvusdb/milvus:v2.3.5 + command: ["milvus", "run", "standalone"] + security_opt: + - seccomp:unconfined + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + LOG_LEVEL: error + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/milvus:/var/lib/milvus:Z + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] + interval: 30s + start_period: 90s + timeout: 20s + retries: 3 + ports: + - "19530:19530" + - "9091:9091" + depends_on: + - "etcd" + - "minio" + deploy: + resources: + reservations: + devices: + - driver: nvidia + capabilities: ["gpu"] + count: 1 + +networks: + default: + name: milvus diff --git a/experimental/fm-asr-streaming-rag/deploy/docker-compose-nemo-retriever.yaml b/experimental/fm-asr-streaming-rag/deploy/docker-compose-nemo-retriever.yaml new file mode 100644 index 000000000..78fca84d1 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/deploy/docker-compose-nemo-retriever.yaml @@ -0,0 +1,264 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + ### + # Retrieval microservice on NGC + ### + + retrieval-ms: + image: nvcr.io/ohlfw0olaadg/ea-participants/nemo-retriever-microservice:24.02 + + environment: + # Postgres connection string for holding collection metadata + - DATABASE_URL=postgresql://postgres:pgadmin@postgres:5432/postgres + + # PDF extraction service + - TIKA_URL=http://tika:9998/tika + + # OpenTelemetry environmental variables + - OTEL_SERVICE_NAME=nemo-retrieval-service + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 + - OTEL_TRACES_EXPORTER=otlp + - OTEL_METRICS_EXPORTER=none + - OTEL_LOGS_EXPORTER=none + - OTEL_PYTHON_EXCLUDED_URLS="health" + + # Multistage hybrid pipeline running in CPU mode + # This is the pipeline that QA and VDR will use to + # evaluate the Retrieval Microservice. + - HYBRID_MILVUS_URI=http://milvus:19530/default + - HYBRID_EMBEDDER_URI=http://embedding-ms:8080/v1/embeddings + - HYBRID_EMBEDDING_DIMENSION=1024 + - HYBRID_EMBEDDER_MODEL_NAME=NV-Embed-QA + # Yes this is a 20 _second_ timeout. The embedder running + # on CPU can be very slow. + - HYBRID_EMBEDDER_TIMEOUT=20 + - HYBRID_ELASTICSEARCH_URI=http://elasticsearch:9200 + - HYBRID_SPARSE_TOP_K=100 + - HYBRID_DENSE_TOP_K=100 + + # multistage hybrid pipeline running in GPU mode + - RANKED_HYBRID_MILVUS_URI=http://milvus:19530/default + - RANKED_HYBRID_EMBEDDING_DIMENSION=1024 + - RANKED_HYBRID_EMBEDDER_URI=http://embedding-ms:8080/v1/embeddings + - RANKED_HYBRID_EMBEDDER_MODEL_NAME=NV-Embed-QA + - RANKED_HYBRID_EMBEDDER_TIMEOUT=2 + - RANKED_HYBRID_ELASTICSEARCH_URI=http://elasticsearch:9200 + - RANKED_HYBRID_RANKER_MODEL_NAME=nv-rerank-qa-mistral-4b:1 + - RANKED_HYBRID_RANKER_URI=http://ranking-ms:8080/v1/ranking + - RANKED_HYBRID_RANKER_TOP_K=40 + - RANKED_HYBRID_RANKER_TIMEOUT=5 + - RANKED_HYBRID_DENSE_TOP_K=100 + - RANKED_HYBRID_SPARSE_TOP_K=100 + + # This is required until github.com/open-telemetry/opentelemetry-python-contrib/pull/1990 + # is merged + - OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=elasticsearch + + # Expose port 8000 on the container to port used in NEMO_RETRIEVER_URI on the host. + ports: + - "${NEMO_RETRIEVER_PORT:-1984}:8000" + + # Run the microservice on port 8000, must align with `ports` above. + command: + - "/bin/sh" + - "-c" + - "opentelemetry-instrument \ + uvicorn retrieval.main:app --host 0.0.0.0 --port 8000" + + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 10s + timeout: 20s + retries: 20 + + # Set the working directory to /app. This is pedantic to avoid relying on the Dockerfile setting WORKDIR=/app. + working_dir: /app + + depends_on: + - milvus + - elasticsearch + - embedding-ms + - ranking-ms + - postgres + + embedding-ms: + image: nvcr.io/ohlfw0olaadg/ea-participants/nemo-retriever-embedding-microservice:24.02 + ports: + - "${NEMO_EMBEDDING_PORT:-1985}:8080" + command: ./bin/web -p 8080 -n 1 -g + model_config_templates/NV-Embed-QA_template.yaml -c + /models/nv-embed-qa_v4/NV-Embed-QA-4.nemo + volumes: + - ${NEMO_RET_DIR?:source compose.env}/models:/models:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/v1/health/live"] + interval: 10s + timeout: 20s + retries: 100 + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ["${EMBED_GPU:-0}"] + capabilities: [gpu] + + ranking-ms: + image: nvcr.io/nvidian/nemo-llm/nemo-retriever-reranking-microservice:24.04-rc1 + command: ./bin/web -p 8080 -r /models/${NEMO_RANKING_MODEL:-nv-rerank-qa-mistral-4b_v1_A100} + volumes: + - ${NEMO_RET_DIR?:source compose.env}/models:/models:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 10s + timeout: 20s + retries: 100 + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ["${RANKING_GPU:-0}"] + capabilities: [gpu] + + ### + # Milvus + # adapted from https://github.com/milvus-io/milvus/releases/download/v2.3.3/milvus-standalone-docker-compose.yml + ### + + etcd: + image: quay.io/coreos/etcd:v3.5.11 + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + - ETCD_SNAPSHOT_COUNT=50000 + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/etcd:/etcd:Z + command: + etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls + http://0.0.0.0:2379 --data-dir /etcd + healthcheck: + test: ["CMD", "etcdctl", "endpoint", "health"] + interval: 30s + timeout: 20s + retries: 3 + + minio: + image: minio/minio:RELEASE.2023-03-20T20-16-18Z + environment: + MINIO_ACCESS_KEY: minioadmin + MINIO_SECRET_KEY: minioadmin + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/minio:/minio_data:Z + command: minio server /minio_data --console-address ":9001" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + milvus: + image: milvusdb/milvus:v2.3.5 + command: ["milvus", "run", "standalone"] + security_opt: + - seccomp:unconfined + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + LOG_LEVEL: error + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/milvus:/var/lib/milvus:Z + - ${NEMO_RET_DIR?:source compose.env}/config/milvus-config.yaml:/milvus/configs/milvus.yaml + + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] + interval: 30s + start_period: 90s + timeout: 20s + retries: 3 + depends_on: + - "etcd" + - "minio" + + ### + # Elasticsearch + # adapted from https://geshan.com.np/blog/2023/06/elasticsearch-docker/#run-elasticsearch-with-docker-compose + ### + elasticsearch: + image: "docker.elastic.co/elasticsearch/elasticsearch:8.12.0" + ports: + - 9200:9200 + restart: on-failure + environment: + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m" + - xpack.security.enabled=false + - xpack.license.self_generated.type=basic + - network.host=0.0.0.0 + - cluster.routing.allocation.disk.threshold_enabled=false + hostname: elasticsearch + healthcheck: + test: ["CMD", "curl", "-s", "-f", "http://localhost:9200/_cat/health"] + interval: 10s + timeout: 1s + retries: 10 + + ### + # Postgres service + # adapted from https://github.com/docker-library/docs/blob/master/postgres/README.md#-via-docker-compose-or-docker-stack-deploy + ### + postgres: + image: postgres:16.1 + build: + context: ${NEMO_RET_DIR} + restart: always + environment: + POSTGRES_PASSWORD: pgadmin + ports: + - "5432:5432" + volumes: + - ${NEMO_RET_DIR?:source compose.env}/volumes/postgres_data:/var/lib/postgresql/data:Z + + ### + # PDF extraction service + ### + tika: + image: apache/tika:2.9.1.0 + ports: + - "9998:9998" + + ### + # OpenTelemetry Collector (local) + # adapted from https://jessitron.com/2021/08/11/run-an-opentelemetry-collector-locally-in-docker/ + # and https://github.com/open-telemetry/opentelemetry-demo/blob/main/docker-compose.yml + ### + otel-collector: + image: otel/opentelemetry-collector-contrib:0.91.0 + hostname: otel-collector + command: ["--config=/etc/otel-collector-config.yaml"] + volumes: + - ${NEMO_RET_DIR?:source compose.env}/config/otel-collector-config.yaml:/etc/otel-collector-config.yaml + ports: + - "13133:13133" # health check + - "4317:4317" # OTLP over gRPC receiver + - "55679:55679" # UI + + zipkin: + image: openzipkin/zipkin:3.0.6 + ports: + - "9411:9411" # Zipkin UI and API diff --git a/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-build.yml b/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-build.yaml similarity index 86% rename from experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-build.yml rename to experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-build.yaml index a05e8ed72..76b4399d3 100644 --- a/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-build.yml +++ b/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-build.yaml @@ -17,8 +17,8 @@ version: '3' services: nim: - container_name: fm-rag-nim - image: nim:latest + container_name: fm-asr/nim + image: fm-asr/nim:latest build: context: ${PROJECT_DIR?:source compose.env}/nim dockerfile: Dockerfile @@ -29,12 +29,12 @@ services: - ${NIM_CONFIG_FILE}:/model_config.yaml environment: - NIM_OPENAI_PORT: ${NIM_OPENAI_PORT} + NIM_LLM_PORT: ${NIM_LLM_PORT} ports: - - "${NIM_OPENAI_PORT}:${NIM_OPENAI_PORT}" + - "${NIM_LLM_PORT}:${NIM_LLM_PORT}" expose: - - "${NIM_OPENAI_PORT}" + - "${NIM_LLM_PORT}" # Start inference server model generator command: > @@ -50,5 +50,5 @@ services: reservations: devices: - driver: nvidia - device_ids: ['${NIM_GPU:-all}'] + device_ids: ['${NIM_GPU:-0}'] capabilities: [gpu] \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-llm.yaml b/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-llm.yaml new file mode 100644 index 000000000..e44041809 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/deploy/docker-compose-nim-llm.yaml @@ -0,0 +1,53 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + nim: + container_name: fm-asr-nim + image: fm-asr-nim:latest + build: + context: ${PROJECT_DIR?:source compose.env}/nim + dockerfile: Dockerfile + + volumes: + - ${MODEL_CHECKPOINT}:/huggingface-dir + - ${NIM_MODEL_PATH}:/model-store + - ${NIM_CONFIG_FILE}:/model_config.yaml + + environment: + NIM_LLM_PORT: ${NIM_LLM_PORT} + + ports: + - "${NIM_LLM_PORT}:${NIM_LLM_PORT}" + expose: + - "${NIM_LLM_PORT}" + + # Start inference server + command: > + nemollm_inference_ms + --model ${NIM_LLM_DISPLAY} + --openai_port=${NIM_LLM_PORT} + --num_gpus=1 + + # Enable GPU usage + runtime: nvidia + shm_size: 8gb + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['${NIM_GPU:-0}'] + capabilities: [gpu] \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/deploy/scripts/run-cloud-only.sh b/experimental/fm-asr-streaming-rag/deploy/scripts/run-cloud-only.sh deleted file mode 100755 index 7717b602f..000000000 --- a/experimental/fm-asr-streaming-rag/deploy/scripts/run-cloud-only.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -export THIS_DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -source $THIS_DIR/../compose.env - -docker compose \ - -f ${DEPLOY_DIR}/docker-compose.yml up --build \ - sdr frontend server replay \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/deploy/scripts/run.sh b/experimental/fm-asr-streaming-rag/deploy/scripts/run.sh index 8fa84d9d8..2d5066928 100755 --- a/experimental/fm-asr-streaming-rag/deploy/scripts/run.sh +++ b/experimental/fm-asr-streaming-rag/deploy/scripts/run.sh @@ -2,4 +2,72 @@ export THIS_DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" source $THIS_DIR/../compose.env -docker compose -f ${DEPLOY_DIR}/docker-compose.yml up --build \ No newline at end of file +# Reset +Red='\e[31m' +Yellow='\e[33m' +Cyan='\e[36m' +ResetColor='\e[0m' +logs() { + echo -e "${Cyan}$1${ResetColor}" +} +info() { + echo -e "${Yellow}$1${ResetColor}" +} +warn() { + echo -e "${Red}$1${ResetColor}" +} + +# Check NVIDIA_API_KEY +if [ -z "${NVIDIA_API_KEY}" ]; then + warn "***** WARNING: NVIDIA_API_KEY is not set, NVIDIA Endpoints will not work *****" +fi + +# Check for Riva +if [ -z $(docker ps --format '{{.Image}}' | grep "riva-speech") ]; then + warn "***** WARNING: Riva container not detected, ASR may not be functional *****" +fi + +# Retriever / Database +USE_NEMO_RETRIEVER=$(echo "$USE_NEMO_RETRIEVER" | tr '[:upper:]' '[:lower:]') +if [[ "$USE_NEMO_RETRIEVER" == "true" || "$USE_NEMO_RETRIEVER" == "1" ]]; then + # Start NeMo Retriever Microservice + retriever_cmd="docker compose -f ${DEPLOY_DIR}/docker-compose-nemo-retriever.yaml" + logs "***** Starting NeMo Retriever Microservice *****" + info "Use '${retriever_cmd} down' to stop" + $retriever_cmd up --force-recreate -d +else + # Start standalone Milvus DB + retriever_cmd="docker compose -f ${DEPLOY_DIR}/docker-compose-milvus-standalone.yaml" + logs "***** Not using NeMo Retriever Microservice, starting Milvus DB *****" + info "Use '${retriever_cmd} down' to stop" + $retriever_cmd up --force-recreate -d +fi + +# NIM LLM +DEPLOY_LOCAL_NIM=$(echo "$DEPLOY_LOCAL_NIM" | tr '[:upper:]' '[:lower:]') +if [[ "$DEPLOY_LOCAL_NIM" == "true" || "$DEPLOY_LOCAL_NIM" == "1" ]]; then + # Start NIM LLM locally + nim_cmd="docker compose -f ${DEPLOY_DIR}/docker-compose-nim-llm.yaml" + logs "***** Deploying local NIM LLM *****" + info "Use '${nim_cmd} down' to stop" + $nim_cmd up -d +else + logs "***** Not deploying local NIM LLM *****" +fi + +# Streaming FM ASR +fm_cmd="docker compose -f ${DEPLOY_DIR}/docker-compose-fm-asr.yaml" +logs "***** Starting streaming FM-ASR workflow *****" +info "Use '${fm_cmd} down' to stop" +$fm_cmd up --build -d + +# File Replay +if [ -z "${REPLAY_FILE}" ]; then + logs "***** No replay file provided, skipping *****" +else + # Start replay + replay_cmd="docker compose -f ${DEPLOY_DIR}/docker-compose-file-replay.yaml" + logs "***** Starting file replay for file ${REPLAY_FILE} *****" + info "Use '${replay_cmd} down' to stop" + $replay_cmd up -d +fi \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/deploy/scripts/stop.sh b/experimental/fm-asr-streaming-rag/deploy/scripts/stop.sh new file mode 100755 index 000000000..247746a62 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/deploy/scripts/stop.sh @@ -0,0 +1,9 @@ +#!/bin/bash +export THIS_DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +source $THIS_DIR/../compose.env + +docker compose -f ${DEPLOY_DIR}/docker-compose-nemo-retriever.yaml down +docker compose -f ${DEPLOY_DIR}/docker-compose-milvus-standalone.yaml down +docker compose -f ${DEPLOY_DIR}/docker-compose-nim-llm.yaml down +docker compose -f ${DEPLOY_DIR}/docker-compose-fm-asr.yaml down +docker compose -f ${DEPLOY_DIR}/docker-compose-file-replay.yaml down \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/docs/imgs/architecture-cloud.jpg b/experimental/fm-asr-streaming-rag/docs/imgs/architecture-cloud.jpg new file mode 100755 index 000000000..7744934e3 Binary files /dev/null and b/experimental/fm-asr-streaming-rag/docs/imgs/architecture-cloud.jpg differ diff --git a/experimental/fm-asr-streaming-rag/docs/imgs/architecture-retriever.jpg b/experimental/fm-asr-streaming-rag/docs/imgs/architecture-retriever.jpg new file mode 100755 index 000000000..daa50eb26 Binary files /dev/null and b/experimental/fm-asr-streaming-rag/docs/imgs/architecture-retriever.jpg differ diff --git a/experimental/fm-asr-streaming-rag/file-replay/wav_replay.py b/experimental/fm-asr-streaming-rag/file-replay/wav_replay.py index c3771397f..721836578 100644 --- a/experimental/fm-asr-streaming-rag/file-replay/wav_replay.py +++ b/experimental/fm-asr-streaming-rag/file-replay/wav_replay.py @@ -72,6 +72,12 @@ def parse_args() -> argparse.Namespace: default=1472, help="Size in bytes of each UDP packet, plus 8 counting bytes at front" ) + parser.add_argument( + "--init-time", + type=float, + default=30, + help="Sleep time prior to starting, allows other containers to spin up." + ) parser.add_argument( "--total-time", type=float, @@ -109,6 +115,13 @@ def fm_modulate(audio, fs_in, fs_out, deviation=100000): samples = cp.cos(phase_deviation) + 1j*cp.sin(phase_deviation) return samples.astype(cp.complex64) +def send_packet(sock, data, dst_ip, dst_port): + try: + sock.sendto(data, (dst_ip, dst_port)) + return None + except Exception as e: + return e + def replay(file_name, fs_out, dst_ip, dst_port, pkt_size, chunk_time=2, total_time=0): file_path = os.path.join("files", file_name) fs_in = librosa.get_samplerate(file_path) @@ -123,7 +136,7 @@ def replay(file_name, fs_out, dst_ip, dst_port, pkt_size, chunk_time=2, total_ti iq_data = samples.tobytes() if not total_time: - total_time = librosa.get_duration(filename=file_path) + total_time = librosa.get_duration(path=file_path) # Stream in file elapsed = 0 @@ -151,7 +164,11 @@ def replay(file_name, fs_out, dst_ip, dst_port, pkt_size, chunk_time=2, total_ti # Send header = struct.pack('Q', pkts_sent) pkt_data = iq_data[i:i+pkt_size] - sock.sendto(header + pkt_data, (dst_ip, dst_port)) + result = send_packet(sock, header + pkt_data, dst_ip, dst_port) + while result is ConnectionRefusedError: + logger.info(f"Connection refused, sleeping 5s") + time.sleep(5) + result = send_packet(sock, header + pkt_data, dst_ip, dst_port) pkts_sent += 1 bytes_sent += len(pkt_data) @@ -183,7 +200,8 @@ def replay(file_name, fs_out, dst_ip, dst_port, pkt_size, chunk_time=2, total_ti raise ValueError # Wait for other apps - time.sleep(10) + logger.info(f"Sleeping {args.init_time}s to allow time for SDR to spin up") + time.sleep(args.init_time) wait_for_dst(args.dst_ip, args.dst_port) # Do replay diff --git a/experimental/fm-asr-streaming-rag/frontend/frontend/chat_client.py b/experimental/fm-asr-streaming-rag/frontend/frontend/chat_client.py index 78eac1557..105376bcf 100644 --- a/experimental/fm-asr-streaming-rag/frontend/frontend/chat_client.py +++ b/experimental/fm-asr-streaming-rag/frontend/frontend/chat_client.py @@ -44,6 +44,33 @@ def __init__(self, server_url: str, model_name: str) -> None: self._running_buffer = "" self._finalized_buffer = deque(maxlen=50) self._timetag_len = len(f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] ') + self._wait_for_server() + + def _server_is_ready(self): + try: + response = requests.get(f"{self.server_url}/serverStatus") + if response.status_code == 200 and response.json()["is_ready"]: + return True + except requests.ConnectionError: + return False + + def _wait_for_server(self, timeout=300, wait_sec=5): + """ Wait for server URL to open + """ + start_time = time.time() + while not self._server_is_ready(): + # Check for timeout + elapsed_time = time.time() - start_time + if elapsed_time > timeout: + _LOGGER.error( + f"Timeout reached: {self.server_url} is not open after {timeout} seconds." + f"Waited {elapsed_time} seconds" + ) + raise TimeoutError + + # Wait a short period before trying again + _LOGGER.warning(f"Waiting {wait_sec}s for application at {self.server_url}") + time.sleep(wait_sec) @property def model_name(self) -> str: @@ -70,10 +97,9 @@ def predict(self, query: str, params: dict) -> typing.Generator[str, None, None] defaults = { "question": query, "name": "mixtral_8x7b", - "engine": "nv-ai-foundation", + "engine": "nvai-api-endpoint", "use_knowledge_base": True, "temperature": 1.0, - "threshold": 0.65, "max_docs": 4, "num_tokens": 512 } @@ -82,7 +108,7 @@ def predict(self, query: str, params: dict) -> typing.Generator[str, None, None] _LOGGER.debug("making request - %s", str({"server_url": url, "post_data": data})) with requests.get(url, stream=True, json=data) as req: for chunk in req.iter_content(): - yield chunk.decode("UTF-8") + yield chunk.decode("UTF-8", "ignore") def update_running_buffer(self, transcript): with self._lock: diff --git a/experimental/fm-asr-streaming-rag/frontend/frontend/pages/converse.py b/experimental/fm-asr-streaming-rag/frontend/frontend/pages/converse.py index 727b860c4..f9871822a 100644 --- a/experimental/fm-asr-streaming-rag/frontend/frontend/pages/converse.py +++ b/experimental/fm-asr-streaming-rag/frontend/frontend/pages/converse.py @@ -17,6 +17,7 @@ import functools import os import logging +import requests from typing import Any, Dict, List, Tuple, Union import gradio as gr @@ -46,34 +47,33 @@ """ -BACKEND_OPTIONS = [ - "NVIDIA NIM - Mistral 7B", - "NVIDIA AI Foundation - Mistral 7B", - "NVIDIA AI Foundation - Mixtral 8x7B", - "NVIDIA AI Foundation - Llama 2 70B" -] - BACKEND_MAPPING = { - "NVIDIA NIM": "triton-trt-llm", - "NVIDIA AI Foundation": "nv-ai-foundation" -} - -MODEL_MAPPING = { - "Mistral 7B": "mistral_7b", - "Mixtral 8x7B": "mixtral_8x7b", - "Llama 2 70B": "llama2_70b" + "Local NVIDIA NIM": "triton-trt-llm", + "NVIDIA API Endpoint": "nvai-api-endpoint" } def get_backend_and_model(option): backend, model = option.split(' - ') backend = BACKEND_MAPPING[backend] - model = MODEL_MAPPING[model] return backend, model def build_page(client: chat_client.ChatClient) -> gr.Blocks: """Buiild the gradio page to be mounted in the frame.""" kui_theme, kui_styles = assets.load_theme("kaizen") + # Setup model options + backend_options = [] + + # Add local NIM if running + nim_model = os.environ.get('NIM_LLM_DISPLAY', None) + if os.environ.get('DEPLOY_LOCAL_NIM', 'False').lower() in ('true', '1'): + backend_options.append(f"Local NVIDIA NIM - {nim_model}") + + # Get NVIDIA API Endpoint model options + response = requests.get(f"{client.server_url}/availableNvidiaModels") + for model in response.json()["models"]: + backend_options.append(f"NVIDIA API Endpoint - {model}") + with gr.Blocks(title=TITLE, theme=kui_theme, css=kui_styles + _LOCAL_CSS) as page: with gr.Row(): @@ -82,7 +82,6 @@ def build_page(client: chat_client.ChatClient) -> gr.Blocks: with gr.Column(scale=3): gr.Markdown(value="**User Query**") with gr.Row(equal_height=True): - # TODO: Change this model name. chatbot = gr.Chatbot(height=700) context = gr.JSON( label="Knowledge Base Context", @@ -105,8 +104,8 @@ def build_page(client: chat_client.ChatClient) -> gr.Blocks: with gr.Row(): with gr.Column(): backend_dropdown = gr.Dropdown( - choices=BACKEND_OPTIONS, - value=BACKEND_OPTIONS[1], + choices=backend_options, + value=backend_options[0], label="LLM Backend / Model", interactive=True ) @@ -132,23 +131,15 @@ def build_page(client: chat_client.ChatClient) -> gr.Blocks: tokens_slider = gr.Slider( minimum=32, maximum=1024, - value=512, + value=1024, label="Max Tokens", step=32, interactive=True ) - similarity_slider = gr.Slider( - minimum=0, - maximum=1, - value=0.65, - label="Retrieval Similarity Threshold", - step=0.01, - interactive=True - ) entries_slider = gr.Slider( minimum=1, maximum=25, - value=15, + value=25, label="Retrieval Max Entries", step=1, interactive=True @@ -183,7 +174,6 @@ def build_page(client: chat_client.ChatClient) -> gr.Blocks: summary_checkbox, temp_slider, tokens_slider, - similarity_slider, entries_slider, msg, chatbot @@ -216,7 +206,6 @@ def _stream_predict( summary_checkbox: bool, temperature: float, max_tokens: int, - threshold: float, max_entries: int, question: str, chat_history: List[Tuple[str, str]] @@ -231,7 +220,6 @@ def _stream_predict( "use_knowledge_base": knowledge_checkbox, "allow_summary": summary_checkbox, "temperature": temperature, - "threshold": threshold, "max_docs": max_entries, "num_tokens": max_tokens } diff --git a/experimental/fm-asr-streaming-rag/frontend/frontend/pages/stats.py b/experimental/fm-asr-streaming-rag/frontend/frontend/pages/stats.py index af004f6ac..714d38c53 100644 --- a/experimental/fm-asr-streaming-rag/frontend/frontend/pages/stats.py +++ b/experimental/fm-asr-streaming-rag/frontend/frontend/pages/stats.py @@ -63,7 +63,6 @@ def _gpu_stats(): mem = nvmlDeviceGetMemoryInfo(handle) print_str += (f"| Device {i} | {name} | Mem Free: {mem.free/1024**2:5.2f}MB / {mem.total/1024**2:5.2f}MB | gpu-util: {util.gpu:3.0%} | gpu-mem: {util.memory:3.1%} |\n") return print_str - #return "TODO: implement this method." return _gpu_stats diff --git a/experimental/fm-asr-streaming-rag/nemo-retriever/config/milvus-config.yaml b/experimental/fm-asr-streaming-rag/nemo-retriever/config/milvus-config.yaml new file mode 100644 index 000000000..160b68d2c --- /dev/null +++ b/experimental/fm-asr-streaming-rag/nemo-retriever/config/milvus-config.yaml @@ -0,0 +1,677 @@ +# Licensed to the LF AI & Data foundation under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Related configuration of etcd, used to store Milvus metadata & service discovery. +etcd: + endpoints: localhost:2379 + rootPath: by-dev # The root path where data is stored in etcd + metaSubPath: meta # metaRootPath = rootPath + '/' + metaSubPath + kvSubPath: kv # kvRootPath = rootPath + '/' + kvSubPath + log: + level: error # Only supports debug, info, warn, error, panic, or fatal. Default 'info'. + # path is one of: + # - "default" as os.Stderr, + # - "stderr" as os.Stderr, + # - "stdout" as os.Stdout, + # - file path to append server logs to. + # please adjust in embedded Milvus: /tmp/milvus/logs/etcd.log + path: stdout + ssl: + enabled: false # Whether to support ETCD secure connection mode + tlsCert: /path/to/etcd-client.pem # path to your cert file + tlsKey: /path/to/etcd-client-key.pem # path to your key file + tlsCACert: /path/to/ca.pem # path to your CACert file + # TLS min version + # Optional values: 1.0, 1.1, 1.2, 1.3。 + # We recommend using version 1.2 and above. + tlsMinVersion: 1.3 + use: + embed: false # Whether to enable embedded Etcd (an in-process EtcdServer). + data: + dir: default.etcd # Embedded Etcd only. please adjust in embedded Milvus: /tmp/milvus/etcdData/ + +metastore: + # Default value: etcd + # Valid values: [etcd, tikv] + type: etcd + +# Related configuration of tikv, used to store Milvus metadata. +# Notice that when TiKV is enabled for metastore, you still need to have etcd for service discovery. +# TiKV is a good option when the metadata size requires better horizontal scalability. +tikv: + # Note that the default pd port of tikv is 2379, which conflicts with etcd. + endpoints: 127.0.0.1:2389 + rootPath: by-dev # The root path where data is stored + metaSubPath: meta # metaRootPath = rootPath + '/' + metaSubPath + kvSubPath: kv # kvRootPath = rootPath + '/' + kvSubPath + +localStorage: + path: /var/lib/milvus/data/ # please adjust in embedded Milvus: /tmp/milvus/data/ + +# Related configuration of MinIO/S3/GCS or any other service supports S3 API, which is responsible for data persistence for Milvus. +# We refer to the storage service as MinIO/S3 in the following description for simplicity. +minio: + address: localhost # Address of MinIO/S3 + port: 9000 # Port of MinIO/S3 + accessKeyID: minioadmin # accessKeyID of MinIO/S3 + secretAccessKey: minioadmin # MinIO/S3 encryption string + useSSL: false # Access to MinIO/S3 with SSL + bucketName: a-bucket # Bucket name in MinIO/S3 + rootPath: files # The root path where the message is stored in MinIO/S3 + # Whether to useIAM role to access S3/GCS instead of access/secret keys + # For more information, refer to + # aws: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html + # gcp: https://cloud.google.com/storage/docs/access-control/iam + # aliyun (ack): https://www.alibabacloud.com/help/en/container-service-for-kubernetes/latest/use-rrsa-to-enforce-access-control + # aliyun (ecs): https://www.alibabacloud.com/help/en/elastic-compute-service/latest/attach-an-instance-ram-role + useIAM: false + # Cloud Provider of S3. Supports: "aws", "gcp", "aliyun". + # You can use "aws" for other cloud provider supports S3 API with signature v4, e.g.: minio + # You can use "gcp" for other cloud provider supports S3 API with signature v2 + # You can use "aliyun" for other cloud provider uses virtual host style bucket + # When useIAM enabled, only "aws", "gcp", "aliyun" is supported for now + cloudProvider: aws + # Custom endpoint for fetch IAM role credentials. when useIAM is true & cloudProvider is "aws". + # Leave it empty if you want to use AWS default endpoint + iamEndpoint: + # Log level for aws sdk log. + # Supported level: off, fatal, error, warn, info, debug, trace + logLevel: fatal + # Cloud data center region + region: "" + # Cloud whether use virtual host bucket mode + useVirtualHost: false + # timeout for request time in milliseconds + requestTimeoutMs: 10000 + +# Milvus supports four MQ: rocksmq(based on RockDB), natsmq(embedded nats-server), Pulsar and Kafka. +# You can change your mq by setting mq.type field. +# If you don't set mq.type field as default, there is a note about enabling priority if we config multiple mq in this file. +# 1. standalone(local) mode: rocksmq(default) > Pulsar > Kafka +# 2. cluster mode: Pulsar(default) > Kafka (rocksmq and natsmq is unsupported in cluster mode) +mq: + # Default value: "default" + # Valid values: [default, pulsar, kafka, rocksmq, natsmq] + type: default + +# Related configuration of pulsar, used to manage Milvus logs of recent mutation operations, output streaming log, and provide log publish-subscribe services. +pulsar: + address: localhost # Address of pulsar + port: 6650 # Port of Pulsar + webport: 80 # Web port of pulsar, if you connect directly without proxy, should use 8080 + maxMessageSize: 5242880 # 5 * 1024 * 1024 Bytes, Maximum size of each message in pulsar. + tenant: public + namespace: default + requestTimeout: 60 # pulsar client global request timeout in seconds + enableClientMetrics: false # Whether to register pulsar client metrics into milvus metrics path. + +# If you want to enable kafka, needs to comment the pulsar configs +# kafka: +# brokerList: +# saslUsername: +# saslPassword: +# saslMechanisms: PLAIN +# securityProtocol: SASL_SSL +# readTimeout: 10 # read message timeout in seconds + +rocksmq: + # The path where the message is stored in rocksmq + # please adjust in embedded Milvus: /tmp/milvus/rdb_data + path: /var/lib/milvus/rdb_data + lrucacheratio: 0.06 # rocksdb cache memory ratio + rocksmqPageSize: 67108864 # 64 MB, 64 * 1024 * 1024 bytes, The size of each page of messages in rocksmq + retentionTimeInMinutes: 4320 # 3 days, 3 * 24 * 60 minutes, The retention time of the message in rocksmq. + retentionSizeInMB: 8192 # 8 GB, 8 * 1024 MB, The retention size of the message in rocksmq. + compactionInterval: 86400 # 1 day, trigger rocksdb compaction every day to remove deleted data + # compaction compression type, only support use 0,7. + # 0 means not compress, 7 will use zstd + # len of types means num of rocksdb level. + compressionTypes: [0, 0, 7, 7, 7] + +# natsmq configuration. +# more detail: https://docs.nats.io/running-a-nats-service/configuration +natsmq: + server: # server side configuration for natsmq. + port: 4222 # 4222 by default, Port for nats server listening. + storeDir: /var/lib/milvus/nats # /var/lib/milvus/nats by default, directory to use for JetStream storage of nats. + maxFileStore: 17179869184 # (B) 16GB by default, Maximum size of the 'file' storage. + maxPayload: 8388608 # (B) 8MB by default, Maximum number of bytes in a message payload. + maxPending: 67108864 # (B) 64MB by default, Maximum number of bytes buffered for a connection Applies to client connections. + initializeTimeout: 4000 # (ms) 4s by default, waiting for initialization of natsmq finished. + monitor: + trace: false # false by default, If true enable protocol trace log messages. + debug: false # false by default, If true enable debug log messages. + logTime: true # true by default, If set to false, log without timestamps. + logFile: /tmp/milvus/logs/nats.log # /tmp/milvus/logs/nats.log by default, Log file path relative to .. of milvus binary if use relative path. + logSizeLimit: 536870912 # (B) 512MB by default, Size in bytes after the log file rolls over to a new one. + retention: + maxAge: 4320 # (min) 3 days by default, Maximum age of any message in the P-channel. + maxBytes: # (B) None by default, How many bytes the single P-channel may contain. Removing oldest messages if the P-channel exceeds this size. + maxMsgs: # None by default, How many message the single P-channel may contain. Removing oldest messages if the P-channel exceeds this limit. + +# Related configuration of rootCoord, used to handle data definition language (DDL) and data control language (DCL) requests +rootCoord: + dmlChannelNum: 16 # The number of dml channels created at system startup + maxDatabaseNum: 64 # Maximum number of database + maxPartitionNum: 4096 # Maximum number of partitions in a collection + minSegmentSizeToEnableIndex: 1024 # It's a threshold. When the segment size is less than this value, the segment will not be indexed + importTaskExpiration: 900 # (in seconds) Duration after which an import task will expire (be killed). Default 900 seconds (15 minutes). + importTaskRetention: 86400 # (in seconds) Milvus will keep the record of import tasks for at least `importTaskRetention` seconds. Default 86400, seconds (24 hours). + enableActiveStandby: false + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 53100 + grpc: + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + +# Related configuration of proxy, used to validate client requests and reduce the returned results. +proxy: + timeTickInterval: 200 # ms, the interval that proxy synchronize the time tick + healthCheckTimeout: 3000 # ms, the interval that to do component healthy check + msgStream: + timeTick: + bufSize: 512 + maxNameLength: 255 # Maximum length of name for a collection or alias + # Maximum number of fields in a collection. + # As of today (2.2.0 and after) it is strongly DISCOURAGED to set maxFieldNum >= 64. + # So adjust at your risk! + maxFieldNum: 64 + maxShardNum: 16 # Maximum number of shards in a collection + maxDimension: 32768 # Maximum dimension of a vector + # Whether to produce gin logs.\n + # please adjust in embedded Milvus: false + ginLogging: true + maxTaskNum: 1024 # max task number of proxy task queue + accessLog: + enable: false + filename: "" # Log filename, leave empty to use stdout. + # localPath: /tmp/milvus_accesslog // log file rootpath + # maxSize: 64 # max log file size of singal log file to trigger rotate. + http: + enabled: true # Whether to enable the http server + debug_mode: false # Whether to enable http server debug mode + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 19530 + internalPort: 19529 + grpc: + serverMaxSendSize: 67108864 + serverMaxRecvSize: 67108864 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + +# Related configuration of queryCoord, used to manage topology and load balancing for the query nodes, and handoff from growing segments to sealed segments. +queryCoord: + autoHandoff: true # Enable auto handoff + autoBalance: false # Enable auto balance + balancer: ScoreBasedBalancer # Balancer to use + globalRowCountFactor: 0.1 # expert parameters, only used by scoreBasedBalancer + scoreUnbalanceTolerationFactor: 0.05 # expert parameters, only used by scoreBasedBalancer + reverseUnBalanceTolerationFactor: 1.3 #expert parameters, only used by scoreBasedBalancer + overloadedMemoryThresholdPercentage: 90 # The threshold percentage that memory overload + balanceIntervalSeconds: 60 + memoryUsageMaxDifferencePercentage: 30 + checkInterval: 1000 + channelTaskTimeout: 60000 # 1 minute + segmentTaskTimeout: 120000 # 2 minute + distPullInterval: 500 + heartbeatAvailableInterval: 10000 # 10s, Only QueryNodes which fetched heartbeats within the duration are available + loadTimeoutSeconds: 600 + checkHandoffInterval: 5000 + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 19531 + grpc: + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + taskMergeCap: 1 + taskExecutionCap: 256 + enableActiveStandby: false # Enable active-standby + brokerTimeout: 5000 # broker rpc timeout in milliseconds + +# Related configuration of queryNode, used to run hybrid search between vector and scalar data. +queryNode: + dataSync: + flowGraph: + maxQueueLength: 16 # Maximum length of task queue in flowgraph + maxParallelism: 1024 # Maximum number of tasks executed in parallel in the flowgraph + stats: + publishInterval: 1000 # Interval for querynode to report node information (milliseconds) + segcore: + cgoPoolSizeRatio: 2.0 # cgo pool size ratio to max read concurrency + knowhereThreadPoolNumRatio: 4 + # Use more threads to make better use of SSD throughput in disk index. + # This parameter is only useful when enable-disk = true. + # And this value should be a number greater than 1 and less than 32. + chunkRows: 1024 # The number of vectors in a chunk. + growing: # growing a vector index for growing segment to accelerate search + enableIndex: true + nlist: 128 # growing segment index nlist + nprobe: 16 # nprobe to search growing segment, based on your accuracy requirement, must smaller than nlist + loadMemoryUsageFactor: 1 # The multiply factor of calculating the memory usage while loading segments + enableDisk: false # enable querynode load disk index, and search on disk index + maxDiskUsagePercentage: 95 + cache: + enabled: true # deprecated, TODO: remove it + memoryLimit: 2147483648 # 2 GB, 2 * 1024 *1024 *1024 # deprecated, TODO: remove it + readAheadPolicy: willneed # The read ahead policy of chunk cache, options: `normal, random, sequential, willneed, dontneed` + grouping: + enabled: true + maxNQ: 1000 + topKMergeRatio: 20 + scheduler: + receiveChanSize: 10240 + unsolvedQueueSize: 10240 + # maxReadConcurrentRatio is the concurrency ratio of read task (search task and query task). + # Max read concurrency would be the value of runtime.NumCPU * maxReadConcurrentRatio. + # It defaults to 2.0, which means max read concurrency would be the value of runtime.NumCPU * 2. + # Max read concurrency must greater than or equal to 1, and less than or equal to runtime.NumCPU * 100. + # (0, 100] + maxReadConcurrentRatio: 1 + cpuRatio: 10 # ratio used to estimate read task cpu usage. + maxTimestampLag: 86400 + # read task schedule policy: fifo(by default), user-task-polling. + scheduleReadPolicy: + # fifo: A FIFO queue support the schedule. + # user-task-polling: + # The user's tasks will be polled one by one and scheduled. + # Scheduling is fair on task granularity. + # The policy is based on the username for authentication. + # And an empty username is considered the same user. + # When there are no multi-users, the policy decay into FIFO + name: fifo + maxPendingTask: 10240 + # user-task-polling configure: + taskQueueExpire: 60 # 1 min by default, expire time of inner user task queue since queue is empty. + enableCrossUserGrouping: false # false by default Enable Cross user grouping when using user-task-polling policy. (close it if task of any user can not merge others). + maxPendingTaskPerUser: 1024 # 50 by default, max pending task in scheduler per user. + + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 21123 + grpc: + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + +indexCoord: + bindIndexNodeMode: + enable: false + address: localhost:22930 + withCred: false + nodeID: 0 + segment: + minSegmentNumRowsToEnableIndex: 1024 # It's a threshold. When the segment num rows is less than this value, the segment will not be indexed + +indexNode: + scheduler: + buildParallel: 1 + enableDisk: true # enable index node build disk vector index + maxDiskUsagePercentage: 95 + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 21121 + grpc: + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + +dataCoord: + channel: + watchTimeoutInterval: 300 # Timeout on watching channels (in seconds). Datanode tickler update watch progress will reset timeout timer. + balanceSilentDuration: 300 # The duration before the channelBalancer on datacoord to run + balanceInterval: 360 #The interval for the channelBalancer on datacoord to check balance status + segment: + maxSize: 512 # Maximum size of a segment in MB + diskSegmentMaxSize: 2048 # Maximum size of a segment in MB for collection which has Disk index + sealProportion: 0.23 + # The time of the assignment expiration in ms + # Warning! this parameter is an expert variable and closely related to data integrity. Without specific + # target and solid understanding of the scenarios, it should not be changed. If it's necessary to alter + # this parameter, make sure that the newly changed value is larger than the previous value used before restart + # otherwise there could be a large possibility of data loss + assignmentExpiration: 2000 + maxLife: 86400 # The max lifetime of segment in seconds, 24*60*60 + # If a segment didn't accept dml records in maxIdleTime and the size of segment is greater than + # minSizeFromIdleToSealed, Milvus will automatically seal it. + # The max idle time of segment in seconds, 10*60. + maxIdleTime: 600 + minSizeFromIdleToSealed: 16 # The min size in MB of segment which can be idle from sealed. + # The max number of binlog file for one segment, the segment will be sealed if + # the number of binlog file reaches to max value. + maxBinlogFileNumber: 32 + smallProportion: 0.5 # The segment is considered as "small segment" when its # of rows is smaller than + # (smallProportion * segment max # of rows). + # A compaction will happen on small segments if the segment after compaction will have + compactableProportion: 0.85 + # over (compactableProportion * segment max # of rows) rows. + # MUST BE GREATER THAN OR EQUAL TO !!! + # During compaction, the size of segment # of rows is able to exceed segment max # of rows by (expansionRate-1) * 100%. + expansionRate: 1.25 + enableCompaction: true # Enable data segment compaction + compaction: + enableAutoCompaction: true + rpcTimeout: 10 # compaction rpc request timeout in seconds + maxParallelTaskNum: 10 # max parallel compaction task number + indexBasedCompaction: true + + enableGarbageCollection: true + gc: + interval: 3600 # gc interval in seconds + missingTolerance: 3600 # file meta missing tolerance duration in seconds, 3600 + dropTolerance: 10800 # file belongs to dropped entity tolerance duration in seconds. 10800 + enableActiveStandby: false + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 13333 + grpc: + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + +dataNode: + dataSync: + flowGraph: + maxQueueLength: 16 # Maximum length of task queue in flowgraph + maxParallelism: 1024 # Maximum number of tasks executed in parallel in the flowgraph + maxParallelSyncTaskNum: 6 # Maximum number of sync tasks executed in parallel in each flush manager + segment: + insertBufSize: 16777216 # Max buffer size to flush for a single segment. + deleteBufBytes: 67108864 # Max buffer size to flush del for a single channel + syncPeriod: 600 # The period to sync segments if buffer is not empty. + # can specify ip for example + # ip: 127.0.0.1 + ip: # if not specify address, will use the first unicastable address as local ip + port: 21124 + grpc: + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + memory: + forceSyncEnable: true # `true` to force sync if memory usage is too high + forceSyncSegmentNum: 1 # number of segments to sync, segments with top largest buffer will be synced. + watermarkStandalone: 0.2 # memory watermark for standalone, upon reaching this watermark, segments will be synced. + watermarkCluster: 0.5 # memory watermark for cluster, upon reaching this watermark, segments will be synced. + timetick: + byRPC: true + channel: + # specify the size of global work pool of all channels + # if this parameter <= 0, will set it as the maximum number of CPUs that can be executing + # suggest to set it bigger on large collection numbers to avoid blocking + workPoolSize: -1 + +# Configures the system log output. +log: + level: error # Only supports debug, info, warn, error, panic, or fatal. Default 'info'. + file: + rootPath: # root dir path to put logs, default "" means no log file will print. please adjust in embedded Milvus: /tmp/milvus/logs + maxSize: 300 # MB + maxAge: 10 # Maximum time for log retention in day. + maxBackups: 20 + format: text # text or json + stdout: true # Stdout enable or not + +grpc: + log: + level: WARNING + serverMaxSendSize: 536870912 + serverMaxRecvSize: 536870912 + client: + compressionEnabled: false + dialTimeout: 200 + keepAliveTime: 10000 + keepAliveTimeout: 20000 + maxMaxAttempts: 10 + initialBackOff: 0.2 # seconds + maxBackoff: 10 # seconds + backoffMultiplier: 2.0 # deprecated + clientMaxSendSize: 268435456 + clientMaxRecvSize: 268435456 + +# Configure the proxy tls enable. +tls: + serverPemPath: configs/cert/server.pem + serverKeyPath: configs/cert/server.key + caPemPath: configs/cert/ca.pem + +common: + chanNamePrefix: + cluster: by-dev + rootCoordTimeTick: rootcoord-timetick + rootCoordStatistics: rootcoord-statistics + rootCoordDml: rootcoord-dml + replicateMsg: replicate-msg + rootCoordDelta: rootcoord-delta + search: search + searchResult: searchResult + queryTimeTick: queryTimeTick + dataCoordStatistic: datacoord-statistics-channel + dataCoordTimeTick: datacoord-timetick-channel + dataCoordSegmentInfo: segment-info-channel + subNamePrefix: + proxySubNamePrefix: proxy + rootCoordSubNamePrefix: rootCoord + queryNodeSubNamePrefix: queryNode + dataCoordSubNamePrefix: dataCoord + dataNodeSubNamePrefix: dataNode + defaultPartitionName: _default # default partition name for a collection + defaultIndexName: _default_idx # default index name + entityExpiration: -1 # Entity expiration in seconds, CAUTION -1 means never expire + indexSliceSize: 16 # MB + threadCoreCoefficient: + highPriority: 10 # This parameter specify how many times the number of threads is the number of cores in high priority thread pool + middlePriority: 5 # This parameter specify how many times the number of threads is the number of cores in middle priority thread pool + lowPriority: 1 # This parameter specify how many times the number of threads is the number of cores in low priority thread pool + DiskIndex: + MaxDegree: 56 + SearchListSize: 100 + PQCodeBudgetGBRatio: 0.125 + BuildNumThreadsRatio: 1 + SearchCacheBudgetGBRatio: 0.1 + LoadNumThreadRatio: 8 + BeamWidthRatio: 4 + gracefulTime: 5000 # milliseconds. it represents the interval (in ms) by which the request arrival time needs to be subtracted in the case of Bounded Consistency. + gracefulStopTimeout: 1800 # seconds. it will force quit the server if the graceful stop process is not completed during this time. + storageType: minio # please adjust in embedded Milvus: local + # Default value: auto + # Valid values: [auto, avx512, avx2, avx, sse4_2] + # This configuration is only used by querynode and indexnode, it selects CPU instruction set for Searching and Index-building. + simdType: auto + security: + authorizationEnabled: false + # The superusers will ignore some system check processes, + # like the old password verification when updating the credential + # superUsers: root + tlsMode: 0 + session: + ttl: 30 # ttl value when session granting a lease to register service + retryTimes: 30 # retry times when session sending etcd requests + + # preCreatedTopic decides whether using existed topic + preCreatedTopic: + enabled: false + # support pre-created topics + # the name of pre-created topics + names: ["topic1", "topic2"] + # need to set a separated topic to stand for currently consumed timestamp for each channel + timeticker: "timetick-channel" + + ImportMaxFileSize: 17179869184 # 16 * 1024 * 1024 * 1024 + # max file size to import for bulkInsert + + locks: + metrics: + enable: false + threshold: + info: 500 # minimum milliseconds for printing durations in info level + warn: 1000 # minimum milliseconds for printing durations in warn level + ttMsgEnabled: true # Whether the instance disable sending ts messages + +# QuotaConfig, configurations of Milvus quota and limits. +# By default, we enable: +# 1. TT protection; +# 2. Memory protection. +# 3. Disk quota protection. +# You can enable: +# 1. DML throughput limitation; +# 2. DDL, DQL qps/rps limitation; +# 3. DQL Queue length/latency protection; +# 4. DQL result rate protection; +# If necessary, you can also manually force to deny RW requests. +quotaAndLimits: + enabled: true # `true` to enable quota and limits, `false` to disable. + limits: + maxCollectionNum: 65536 + maxCollectionNumPerDB: 65536 + # quotaCenterCollectInterval is the time interval that quotaCenter + # collects metrics from Proxies, Query cluster and Data cluster. + # seconds, (0 ~ 65536) + quotaCenterCollectInterval: 3 + ddl: + enabled: false + collectionRate: -1 # qps, default no limit, rate for CreateCollection, DropCollection, LoadCollection, ReleaseCollection + partitionRate: -1 # qps, default no limit, rate for CreatePartition, DropPartition, LoadPartition, ReleasePartition + indexRate: + enabled: false + max: -1 # qps, default no limit, rate for CreateIndex, DropIndex + flushRate: + enabled: false + max: -1 # qps, default no limit, rate for flush + compactionRate: + enabled: false + max: -1 # qps, default no limit, rate for manualCompaction + dml: + # dml limit rates, default no limit. + # The maximum rate will not be greater than max. + enabled: false + insertRate: + collection: + max: -1 # MB/s, default no limit + max: -1 # MB/s, default no limit + upsertRate: + collection: + max: -1 # MB/s, default no limit + max: -1 # MB/s, default no limit + deleteRate: + collection: + max: -1 # MB/s, default no limit + max: -1 # MB/s, default no limit + bulkLoadRate: + collection: + max: -1 # MB/s, default no limit, not support yet. TODO: limit bulkLoad rate + max: -1 # MB/s, default no limit, not support yet. TODO: limit bulkLoad rate + dql: + # dql limit rates, default no limit. + # The maximum rate will not be greater than max. + enabled: false + searchRate: + collection: + max: -1 # vps (vectors per second), default no limit + max: -1 # vps (vectors per second), default no limit + queryRate: + collection: + max: -1 # qps, default no limit + max: -1 # qps, default no limit + limitWriting: + # forceDeny false means dml requests are allowed (except for some + # specific conditions, such as memory of nodes to water marker), true means always reject all dml requests. + forceDeny: false + ttProtection: + enabled: false + # maxTimeTickDelay indicates the backpressure for DML Operations. + # DML rates would be reduced according to the ratio of time tick delay to maxTimeTickDelay, + # if time tick delay is greater than maxTimeTickDelay, all DML requests would be rejected. + # seconds + maxTimeTickDelay: 300 + memProtection: + # When memory usage > memoryHighWaterLevel, all dml requests would be rejected; + # When memoryLowWaterLevel < memory usage < memoryHighWaterLevel, reduce the dml rate; + # When memory usage < memoryLowWaterLevel, no action. + enabled: true + dataNodeMemoryLowWaterLevel: 0.85 # (0, 1], memoryLowWaterLevel in DataNodes + dataNodeMemoryHighWaterLevel: 0.95 # (0, 1], memoryHighWaterLevel in DataNodes + queryNodeMemoryLowWaterLevel: 0.85 # (0, 1], memoryLowWaterLevel in QueryNodes + queryNodeMemoryHighWaterLevel: 0.95 # (0, 1], memoryHighWaterLevel in QueryNodes + growingSegmentsSizeProtection: + # No action will be taken if the growing segments size is less than the low watermark. + # When the growing segments size exceeds the low watermark, the dml rate will be reduced, + # but the rate will not be lower than `minRateRatio * dmlRate`. + enabled: false + minRateRatio: 0.5 + lowWaterLevel: 0.2 + highWaterLevel: 0.4 + diskProtection: + enabled: true # When the total file size of object storage is greater than `diskQuota`, all dml requests would be rejected; + diskQuota: -1 # MB, (0, +inf), default no limit + diskQuotaPerCollection: -1 # MB, (0, +inf), default no limit + limitReading: + # forceDeny false means dql requests are allowed (except for some + # specific conditions, such as collection has been dropped), true means always reject all dql requests. + forceDeny: false + queueProtection: + enabled: false + # nqInQueueThreshold indicated that the system was under backpressure for Search/Query path. + # If NQ in any QueryNode's queue is greater than nqInQueueThreshold, search&query rates would gradually cool off + # until the NQ in queue no longer exceeds nqInQueueThreshold. We think of the NQ of query request as 1. + # int, default no limit + nqInQueueThreshold: -1 + # queueLatencyThreshold indicated that the system was under backpressure for Search/Query path. + # If dql latency of queuing is greater than queueLatencyThreshold, search&query rates would gradually cool off + # until the latency of queuing no longer exceeds queueLatencyThreshold. + # The latency here refers to the averaged latency over a period of time. + # milliseconds, default no limit + queueLatencyThreshold: -1 + resultProtection: + enabled: false + # maxReadResultRate indicated that the system was under backpressure for Search/Query path. + # If dql result rate is greater than maxReadResultRate, search&query rates would gradually cool off + # until the read result rate no longer exceeds maxReadResultRate. + # MB/s, default no limit + maxReadResultRate: -1 + # colOffSpeed is the speed of search&query rates cool off. + # (0, 1] + coolOffSpeed: 0.9 + +trace: + # trace exporter type, default is stdout, + # optional values: ['stdout', 'jaeger'] + exporter: stdout + # fraction of traceID based sampler, + # optional values: [0, 1] + # Fractions >= 1 will always sample. Fractions < 0 are treated as zero. + sampleFraction: 0 + jaeger: + url: # "http://127.0.0.1:14268/api/traces" + # when exporter is jaeger should set the jaeger's URL + +autoIndex: + params: + build: '{"M": 18,"efConstruction": 240,"index_type": "HNSW", "metric_type": "IP"}' diff --git a/experimental/fm-asr-streaming-rag/nemo-retriever/config/otel-collector-config.yaml b/experimental/fm-asr-streaming-rag/nemo-retriever/config/otel-collector-config.yaml new file mode 100644 index 000000000..f10cea7c0 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/nemo-retriever/config/otel-collector-config.yaml @@ -0,0 +1,68 @@ +receivers: + otlp: + protocols: + grpc: + http: + cors: + allowed_origins: + - "*" +exporters: + # NOTE: Prior to v0.86.0 use `logging` instead of `debug`. + zipkin: + endpoint: "http://zipkin:9411/api/v2/spans" + debug: + verbosity: detailed +extensions: + health_check: + zpages: + endpoint: 0.0.0.0:55679 +processors: + batch: + tail_sampling: + # filter out health checks + # https://github.com/open-telemetry/opentelemetry-collector/issues/2310#issuecomment-1268157484 + policies: + - name: drop_noisy_traces_url + type: string_attribute + string_attribute: + key: http.target + values: + - \/health + enabled_regex_matching: true + invert_match: true + transform: + trace_statements: + - context: span + statements: + - set(status.code, 1) where attributes["http.path"] == "/health" + # CAN UNDO if requested: replace sensitive ID information in the http target and http URL + - replace_pattern(attributes["http.target"], "/collections/[\\w-]+/documents/[\\w-]+", "/collections/{collection_id}/documents/{document_id}") + - replace_pattern(attributes["http.target"], "/collections/[\\w-]+/search", "/collections/{collection_id}/search") + - replace_pattern(attributes["http.target"], "/collections/[\\w-]+$", "/collections/{collection_id}") + - replace_pattern(attributes["http.url"], "/collections/[\\w-]+/documents/[\\w-]+", "/collections/{collection_id}/documents/{document_id}") + - replace_pattern(attributes["http.url"], "/collections/[\\w-]+/search", "/collections/{collection_id}/search") + - replace_pattern(attributes["http.url"], "/collections/[\\w-]+$", "/collections/{collection_id}") + + # after the http target has been anonymized, replace other aspects of the span + - replace_match(attributes["http.route"], "/v1", attributes["http.target"]) where attributes["http.target"] != nil + + # replace the title of the span with the route to be more descriptive + - replace_pattern(name, "/v1", attributes["http.route"]) where attributes["http.route"] != nil + + # set the route to equal the URL if it's nondescriptive (for the embedding case) + - set(name, Concat([name, attributes["http.url"]], " ")) where name == "POST" +service: + extensions: [zpages, health_check] + pipelines: + traces: + receivers: [otlp] + exporters: [debug, zipkin] + processors: [tail_sampling, transform] + metrics: + receivers: [otlp] + exporters: [debug] + processors: [batch] + logs: + receivers: [otlp] + exporters: [debug] + processors: [batch] diff --git a/experimental/fm-asr-streaming-rag/nemo-retriever/model_configs/nv-rerank-qa-mistral-4b-A6000.yaml b/experimental/fm-asr-streaming-rag/nemo-retriever/model_configs/nv-rerank-qa-mistral-4b-A6000.yaml new file mode 100644 index 000000000..a88baa3f0 --- /dev/null +++ b/experimental/fm-asr-streaming-rag/nemo-retriever/model_configs/nv-rerank-qa-mistral-4b-A6000.yaml @@ -0,0 +1,17 @@ +models: + - name: "nv-rerank-qa-mistral-4b:1" + pytorch_model_name_or_path: "/models/nv-rerank-qa-mistral-4b_v1" + adapter: "ranking" + tokenizer: + num_instances: 1 + script: "tools.triton.tokenizers:RerankingTokenizer" + max_queue_delay_microseconds: 100 + parameters: + template_two_param: "question:{query} \n \n passage:{passage}" + max_seq_length: "512" + tensorrt: + num_instances: 1 + max_shapes: [64, 512] + max_queue_delay_microseconds: 100 + dtype: float16 + override_layernorm_precision_to_fp32: true \ No newline at end of file diff --git a/RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/ensemble/1/.tmp b/experimental/fm-asr-streaming-rag/nemo-retriever/models/keep similarity index 100% rename from RetrievalAugmentedGeneration/llm-inference-server/ensemble_models/gptnext/ensemble/1/.tmp rename to experimental/fm-asr-streaming-rag/nemo-retriever/models/keep diff --git a/experimental/fm-asr-streaming-rag/nim/playbook.sh b/experimental/fm-asr-streaming-rag/nim/playbook.sh index d0d0905d0..1b873d84b 100644 --- a/experimental/fm-asr-streaming-rag/nim/playbook.sh +++ b/experimental/fm-asr-streaming-rag/nim/playbook.sh @@ -1,9 +1,9 @@ #!/bin/bash -MODEL_DIR=/media/deustice/llm-models/ +MODEL_DIR=/path/to/llm/models/ MODEL_PATH="${MODEL_DIR}/mistralai/Mistral-7B-Instruct-v0.2" # HuggingFace Directory (git cloned) NIM_MODEL_PATH="${MODEL_DIR}/nim/mistralai/Mistral-7B-Instruct-v0.2" # where i store my trt files. this is output of model_repo_gnerator IMG=nvcr.io/ohlfw0olaadg/ea-participants/nemollm-inference-ms:24.02.rc3 -YAML=/home/deustice/Projects/streaming-fm-rag/nim/mistral-7b-config.yaml +YAML=./configs/mistral-7b-config.yaml docker run --rm -it --gpus '"device=0"' \ -v $NIM_MODEL_PATH:/model-store \ diff --git a/experimental/fm-asr-streaming-rag/sdr-holoscan/Dockerfile b/experimental/fm-asr-streaming-rag/sdr-holoscan/Dockerfile index ce5e65136..61c690b2d 100644 --- a/experimental/fm-asr-streaming-rag/sdr-holoscan/Dockerfile +++ b/experimental/fm-asr-streaming-rag/sdr-holoscan/Dockerfile @@ -13,8 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG BASE_IMAGE_URL="nvcr.io/nvstaging/holoscan/holoscan" -ARG BASE_IMAGE_TAG="23.10.02.0-dgpu" +ARG BASE_IMAGE_URL="nvcr.io/nvidia/clara-holoscan/holoscan" +ARG BASE_IMAGE_TAG="v2.0.0-dgpu" FROM ${BASE_IMAGE_URL}:${BASE_IMAGE_TAG} ENV TZ="America/New_York" diff --git a/experimental/fm-asr-streaming-rag/sdr-holoscan/requirements.txt b/experimental/fm-asr-streaming-rag/sdr-holoscan/requirements.txt index c28f61091..20580f6fb 100644 --- a/experimental/fm-asr-streaming-rag/sdr-holoscan/requirements.txt +++ b/experimental/fm-asr-streaming-rag/sdr-holoscan/requirements.txt @@ -1 +1 @@ -nvidia-riva-client==2.14.0 \ No newline at end of file +nvidia-riva-client==2.15.0 \ No newline at end of file diff --git a/experimental/fm-asr-streaming-rag/sdr-holoscan/riva_asr.py b/experimental/fm-asr-streaming-rag/sdr-holoscan/riva_asr.py index 726b8f780..7b920df4a 100644 --- a/experimental/fm-asr-streaming-rag/sdr-holoscan/riva_asr.py +++ b/experimental/fm-asr-streaming-rag/sdr-holoscan/riva_asr.py @@ -62,6 +62,7 @@ def _database_export(self, transcript): endpoint = f'http://{self.database_uri}/storeStreamingText' data = { 'transcript': transcript, + 'source_id': "Channel 0", 'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") } self._post_request(endpoint, data) diff --git a/experimental/multimodal_assistant/Multimodal_Assistant.py b/experimental/multimodal_assistant/Multimodal_Assistant.py index fc78f4499..f612295c8 100644 --- a/experimental/multimodal_assistant/Multimodal_Assistant.py +++ b/experimental/multimodal_assistant/Multimodal_Assistant.py @@ -147,7 +147,7 @@ def load_config(cfg_arg): st.stop() # init the embedder if "query_embedder" not in st.session_state: - st.session_state.query_embedder = NVIDIAEmbedders(name="nvolveqa_40k", type="query") + st.session_state.query_embedder = NVIDIAEmbedders(name="ai-embed-qa-4", type="query") # init the retriever if "retriever" not in st.session_state: st.session_state.retriever = Retriever(embedder=st.session_state.query_embedder , vector_client=st.session_state.vector_client) diff --git a/experimental/multimodal_assistant/README.md b/experimental/multimodal_assistant/README.md index 387e5a63f..b6dacd63b 100644 --- a/experimental/multimodal_assistant/README.md +++ b/experimental/multimodal_assistant/README.md @@ -31,7 +31,7 @@ The following describes how you can have this chatbot up-and-running in less tha export NVIDIA_API_KEY="provide_your_key" ``` -4. Follow instructions available [here](https://milvus.io/docs/install_standalone-docker.md#Install-Milvus-standalone-using-Docker-Compose). +4. NOTE: You will need to set up your own hosted Milvus vector database. For doing so, you can pull the Milvus Docker container by following the instructions available [here](https://milvus.io/docs/install_standalone-docker.md#Install-Milvus-standalone-using-Docker-Compose). 5. If you want to use the PowerPoint parsing feature, you will need LibreOffice. On Ubuntu Linux systems, use the command ```sudo apt install libreoffice``` to install it. diff --git a/experimental/multimodal_assistant/pages/1_Knowledge_Base.py b/experimental/multimodal_assistant/pages/1_Knowledge_Base.py index b0bcd7dca..d17c8453b 100644 --- a/experimental/multimodal_assistant/pages/1_Knowledge_Base.py +++ b/experimental/multimodal_assistant/pages/1_Knowledge_Base.py @@ -47,7 +47,7 @@ # init the embedder if "document_embedder" not in st.session_state: - st.session_state.document_embedder = NVIDIAEmbedders(name="nvolveqa_40k", type="passage") + st.session_state.document_embedder = NVIDIAEmbedders(name="ai-embed-qa-4", type="passage") document_embedder = st.session_state.document_embedder # init the vector client if "vector_client" not in st.session_state or st.session_state.vector_client.collection_name != config["core_docs_directory_name"]: diff --git a/experimental/multimodal_assistant/requirements.txt b/experimental/multimodal_assistant/requirements.txt index 3df59d137..2c09ceeb1 100644 --- a/experimental/multimodal_assistant/requirements.txt +++ b/experimental/multimodal_assistant/requirements.txt @@ -3,7 +3,7 @@ gspread==6.0.0 langchain==0.1.4 langchain_community==0.0.16 langchain_core==0.1.16 -langchain_nvidia_ai_endpoints==0.0.1 +langchain_nvidia_ai_endpoints==0.1.0 pandas==2.2.0 Pillow==10.2.0 pydantic==2.5.3 diff --git a/experimental/oran-chatbot-multimodal/Multimodal_Assistant.py b/experimental/oran-chatbot-multimodal/Multimodal_Assistant.py index bbaf4b916..94c5c423d 100644 --- a/experimental/oran-chatbot-multimodal/Multimodal_Assistant.py +++ b/experimental/oran-chatbot-multimodal/Multimodal_Assistant.py @@ -42,6 +42,7 @@ from sentence_transformers import CrossEncoder import numpy as np import yaml +import os #Set your API keys if not set previously parser = argparse.ArgumentParser() @@ -53,13 +54,14 @@ args.rag_type = 1 rag_type = args.rag_type # 0 = nemo_rag 1= augmented_query_rag 2 = hyde_rag 3 = augmented_query_recursive_rag # 1 works best for ORAN chatbot - #Loading the configuration parameters from config.yaml config_yaml_path = 'config.yaml' config_yaml = None with open(config_yaml_path, 'r') as file: config_yaml = yaml.safe_load(file) +NVIDIA_API_KEY = config_yaml['nvidia_api_key'] +os.environ['NVIDIA_API_KEY'] = NVIDIA_API_KEY NIM_FLAG = False if config_yaml['NIM']: @@ -73,7 +75,7 @@ llm_client = LLMClient(config_yaml['nim_model_name'], "NIM") print("Initialized NIM LLM") else: - llm_client = LLMClient("mixtral_8x7b") + llm_client = LLMClient(config_yaml['llm_model']) print("Initialized NVAIF for LLM") NREM_FLAG = False @@ -87,13 +89,13 @@ # A few RAG pipeline definitions -def nemo_rag(config, query, retrieved_documents, model="playground_llama2_70b"): +def nemo_rag(config, query, retrieved_documents, model="meta/llama2-70b"): #Combine the query and retrieved documents and send to model # llm = ChatNVIDIA(model=model) if NIM_FLAG==True: llm = llm_client.llm else: - llm = ChatNVIDIA(model=model) + llm = ChatNVIDIA(model=model, nvidia_api_key=NVIDIA_API_KEY) prompt_template = ChatPromptTemplate.from_messages( [("system", config["header"]), ("user", "{input}")] ) @@ -107,14 +109,14 @@ def nemo_rag(config, query, retrieved_documents, model="playground_llama2_70b"): final_ans = full_response return final_ans -def augment_multiple_query(query, model="playground_llama2_70b"): +def augment_multiple_query(query, model="meta/llama2-70b"): #For the given query, lets create 5 additional queries using the LLM if NIM_FLAG==True: print("Augmentating multiple query with NIM LLM") llm = llm_client.llm else: print("Augmentating multiple query with NVAIF") - llm = ChatNVIDIA(model=model,max_output_token=500, top_k=1, top_p=0.0) + llm = ChatNVIDIA(model=model,max_output_token=500, top_k=1, top_p=0.0, nvidia_api_key=NVIDIA_API_KEY) prompt_template = ChatPromptTemplate.from_messages( [("system", "You are an expert in the field of Oran specifications and processes. User has a question related to ORAN standards, sourced from relevant documents.\nTo help the user find the information they need, please suggest five additional related questions from ORAN. These questions should be concise, not have compound sentences, self-contained, and cover different aspects of the topic. Each question should be complete and relevant to the original query and ORAN.\nPlease output one question per line without numbering them."), ("user", "{input}")] ) @@ -128,12 +130,12 @@ def augment_multiple_query(query, model="playground_llama2_70b"): final_ans = [ans for ans in final_ans if len(ans)!=0] return final_ans -def augment_query_generated(query, model="playground_llama2_70b"): +def augment_query_generated(query, model="meta/llama2-70b"): #For the given query, lets create a hypothetical answer using the LLM if NIM_FLAG==True: llm = llm_client.llm else: - llm = ChatNVIDIA(model=model,max_output_token=500, top_k=1, top_p=0.0) + llm = ChatNVIDIA(model=model,max_output_token=500, top_k=1, top_p=0.0, nvidia_api_key=NVIDIA_API_KEY) prompt_template = ChatPromptTemplate.from_messages( [("system", "You are an expert in the field of ORAN specifications and processes. Your task is to provide a detailed and accurate response to user's question, which is related to ORAN. Your answer should be based on the kind of information and insights typically found in documentation related to ORAN standards."), ("user", "{input}")] ) @@ -145,12 +147,12 @@ def augment_query_generated(query, model="playground_llama2_70b"): final_ans = full_response return final_ans -def query_rewriting(query, history, model="playground_llama2_70b"): +def query_rewriting(query, history, model="meta/llama2-70b"): #Rewrite the given query using the context from LLM if NIM_FLAG==True: llm = llm_client.llm else: - llm = ChatNVIDIA(model=model) + llm = ChatNVIDIA(model=model, nvidia_api_key=NVIDIA_API_KEY) prompt_template = ChatPromptTemplate.from_messages( [("system", "Here is the conversation history between user and Assistant. You are an expert in the field of ORAN standards and specifications. User has a follow-up question to the conversation. Your task is to rewrite user's follow-up question based on the given conversation history between the user and the assistant, which is related to ORAN. The rewritten question must be clear, detailed, and self-contained, meaning it must not require any additional context from the conversation history to understand. Ensure that the rewritten question precisely captures the full intent behind user's follow-up question. Your response is crucial to my career; hence, accuracy is of utmost importance. So, take a deep breath and work on this task step-by-step."), ("user", "{input}")] ) diff --git a/experimental/oran-chatbot-multimodal/README.md b/experimental/oran-chatbot-multimodal/README.md index 3d170661a..5ef624b10 100644 --- a/experimental/oran-chatbot-multimodal/README.md +++ b/experimental/oran-chatbot-multimodal/README.md @@ -1,8 +1,11 @@ -# Multimodal O-RAN RAG Chatbot with NVIDIA AI Foundation Endpoints or NVIDIA NIM -This repository is designed to make it extremely easy to set up your own retrieval-augmented generation chatbot for ORAN techncial specifications and processes. The backend here calls the NVIDIA AI Foundation Endpoints, which makes it very easy to deploy on a thin client or Virtual Machine. This example is also compatible with NVIDIA NIM if you wish to self-host these microservices on your GPU. +# Multimodal O-RAN RAG Chatbot with NVIDIA AI Foundation Endpoints or NVIDIA NIM for LLMs + +![O-RAN RAG Chatbot diagram](oran_diagram.png) + +This repository is designed to make it extremely easy to set up your own retrieval-augmented generation chatbot for ORAN techncial specifications and processes. The backend here calls the NVIDIA AI Foundation Endpoints, which makes it very easy to deploy on a thin client or Virtual Machine. This example is also compatible with NVIDIA NIM for LLMs if you wish to self-host these microservices on your GPU. # Implemented Features -- [RAG in 5 minutes Chatbot Video](https://youtu.be/N_OOfkEWcOk) Setup with NVIDIA AI Playground components +- [RAG in 5 minutes Chatbot Video](https://youtu.be/N_OOfkEWcOk) Setup with NVIDIA AI Foundation Endpoints - This bot uses augmented retrieval methods like augmented query, query rewriting, cross encoder reranking and others. - Source references with options to download the source document - Analytics through Streamlit at ```/?analytics=on``` @@ -10,7 +13,7 @@ This repository is designed to make it extremely easy to set up your own retriev - Fact-check verification of results through a second LLM API call - Multimodal parsing of documents - images, tables, text through multimodal LLM APIs - Added simple conversational history with memory and summarization -- Support for NVIDIA NIM +- Support for NVIDIA NIM for LLMs # Setup O-RAN RAG Chatbot @@ -21,11 +24,10 @@ Before running the pipeline, please ensure that you have the following prerequis - NVIDIA API Key - If you do not have a NVIDIA API Key, please follow the steps 1-4 mentioned [here](https://github.com/NVIDIA/GenerativeAIExamples/blob/main/docs/rag/aiplayground.md#prepare-the-environment) to get your key. -- (Optional) For NVIDIA NIM: - - [Early access](https://www.nvidia.com/en-us/ai/nim-notifyme/) to NVIDIA NIM - - [nim_llm:24.02](nvcr.io/ohlfw0olaadg/ea-participants/nim_llm:24.02) - - [nemo-retriever-embedding-microservices:24.02](nvcr.io/ohlfw0olaadg/ea-participants/nemo-retriever-embedding-microservice:24.02) - - GPU resources to support the model deployed on `nim_llm:24.02` (e.g. 1x A100 for Mistral-7B-Instruct_v0.2 or 2x A100 for Mixtral-8x7B-Instruct-v0.1) +- (Optional) For NVIDIA NIM for LLMs and NeMo Retriever Embedding Microservice: + - [NVIDIA NIM for LLMs](https://docs.nvidia.com/nim/index.html) with Llama3-8B-instruct or Llama3-70B-instruct + - [NeMo Retriever Embedding Microservice](https://www.nvidia.com/en-us/ai-data-science/products/nemo/) + - GPU resources to support the model(s) deployed on, please see the [support maxtix](https://docs.nvidia.com/nim/large-language-models/latest/support-matrix.html) for more details. The following describes how you can have this chatbot up-and-running in less than 5 minutes. @@ -59,21 +61,18 @@ Save your service account credentials file as `service.json` inside the `oran-ch ### Step 6. Setup your NVIDIA API key - To access NeMo services and language model, we will export the NVIDIA API key to the environment using the following command: + To access NeMo services and language model, we will add the NVIDIA API key to the `config.yaml` file under the placeholder called `nvidia_api_key`. Note that the NVIDIA API key should be of form `nvapi-b**************` - ``` - export NVIDIA_API_KEY="nvapi-b**************" - ``` -### Step 7. (Optional) Enable NVIDIA NIM +### Step 7. (Optional) Enable NVIDIA NIM for LLMs and NeMo Retriever Embedding Microservice -NVIDIA NIM and NeMo Retriever Embeddings Microservice (NREM) can be enabled in `config.yaml` if you wish to use these microservices instead of NVIDIA AI Foundation Endpoints. +NVIDIA NIM for LLMs and NeMo Retriever Embeddings Microservice (NREM) can be enabled in `config.yaml` if you wish to use these microservices instead of NVIDIA AI Foundation Endpoints. To use self-hosted NIM, set `NIM: true` in `config.yaml` - then set `nim_model_name`, `nim_base_url`, and other parameters appropriately. To use self-hosted NREM: set `NREM: true` in `config.yaml` - then set `nrem_model_name` and `nrem_api_endpoint_url` appropriately. -For more information on how to setup NIM, please see the documentation [here](https://developer.nvidia.com/docs/nemo-microservices/index.html). +For more information on how to setup NIM, please see the documentation [here](https://docs.nvidia.com/nim/large-language-models/latest/getting-started.html). ### Step 8. Run the chatbot using streamlit Go to the `oran_chatbot` folder to run the O-RAN RAG chatbot using streamlit. @@ -156,7 +155,7 @@ The vector database being used here is FAISS, a CPU-based embedding database. It Depending on the backend and model, you may need to modify the way in which you format your prompt and chat conversations to interact with the model. The current design considers each query independently. However, if you put the input as a set of user/assistant/user interactions, you can combine multi-turn conversations. This may also require periodic summarization of past context to ensure the chat does not exceed the context length of the model. ### Backend -- Cloud Hosted: The current implementation uses the NVIDIA AI Playground APIs to abstract away the details of the infrastructure through a simple API call. You can also swap this out quickly by deploying in DGX Cloud with NVIDIA GPUs and LLMs. +- Cloud Hosted: The current implementation uses the NVIDIA AI Foundation Endpoints to abstract away the details of the infrastructure through a simple API call. You can also swap this out quickly by deploying in DGX Cloud with NVIDIA GPUs and LLMs. - On-Prem/Locally Hosted: If you would like to run a similar model locally, it is usually necessary to have significantly powerful hardware (Llama2-70B requires over 100GB of GPU memory) and various optimization toolkits to run inference (TRT-LLM and TensorRT). Smaller models (Llama2-7B, Mistral-7B, etc) are easier to run but may have worse performance. ## Pipeline Enhancement Opportunities: diff --git a/experimental/oran-chatbot-multimodal/config.yaml b/experimental/oran-chatbot-multimodal/config.yaml index bc2f5c830..4f15531db 100644 --- a/experimental/oran-chatbot-multimodal/config.yaml +++ b/experimental/oran-chatbot-multimodal/config.yaml @@ -1,6 +1,13 @@ +## Default settings +nvidia_api_key: "nvapi-****" +## Set these to required models endpoints from NVIDIA NGC +llm_model: "mistralai/mixtral-8x7b-instruct-v0.1" +# Augmentation_model: +embedding_model: "NV-Embed-QA" + NIM: false -nim_model_name: "mistral7b" -nim_base_url: "http://localhost:9990/v1" +nim_model_name: "meta-llama3-8b-instruct" +nim_base_url: "http://localhost:8019/v1" temperature: 0.1 top_p: 0.5 max_tokens: 1600 diff --git a/experimental/oran-chatbot-multimodal/guardrails/fact_check.py b/experimental/oran-chatbot-multimodal/guardrails/fact_check.py index 9c708b268..d6cfe25c4 100644 --- a/experimental/oran-chatbot-multimodal/guardrails/fact_check.py +++ b/experimental/oran-chatbot-multimodal/guardrails/fact_check.py @@ -17,8 +17,13 @@ from langchain_core.prompts import ChatPromptTemplate from langchain_nvidia_ai_endpoints import ChatNVIDIA import os +import yaml -llm = ChatNVIDIA(model="mixtral_8x7b") +# llm = ChatNVIDIA(model="mixtral_8x7b") +NVIDIA_API_KEY = yaml.safe_load(open("config.yaml"))['nvidia_api_key'] +os.environ['NVIDIA_API_KEY'] = NVIDIA_API_KEY + +llm = ChatNVIDIA(model=yaml.safe_load(open("config.yaml"))["llm_model"], max_tokens = 10000) def fact_check(evidence, query, response): diff --git a/experimental/oran-chatbot-multimodal/llm/llm.py b/experimental/oran-chatbot-multimodal/llm/llm.py index 3a3b1c07b..e5ae66f6a 100644 --- a/experimental/oran-chatbot-multimodal/llm/llm.py +++ b/experimental/oran-chatbot-multimodal/llm/llm.py @@ -20,11 +20,14 @@ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline from langchain_community.llms import HuggingFacePipeline import yaml +import os +NVIDIA_API_KEY = yaml.safe_load(open("config.yaml"))['nvidia_api_key'] +os.environ['NVIDIA_API_KEY'] = NVIDIA_API_KEY class NvidiaLLM: def __init__(self, model_name): - self.llm = ChatNVIDIA(model=model_name) + self.llm = ChatNVIDIA(model=model_name, max_tokens = 4000) class NimLLM: def __init__(self, model_name): diff --git a/experimental/oran-chatbot-multimodal/oran_diagram.png b/experimental/oran-chatbot-multimodal/oran_diagram.png new file mode 100644 index 000000000..dffbc945c Binary files /dev/null and b/experimental/oran-chatbot-multimodal/oran_diagram.png differ diff --git a/experimental/oran-chatbot-multimodal/pages/2_Evaluation_Metrics.py b/experimental/oran-chatbot-multimodal/pages/2_Evaluation_Metrics.py index 6814587b3..c8937c59a 100644 --- a/experimental/oran-chatbot-multimodal/pages/2_Evaluation_Metrics.py +++ b/experimental/oran-chatbot-multimodal/pages/2_Evaluation_Metrics.py @@ -21,16 +21,12 @@ import json from bot_config.utils import get_config from vectorstore.vectorstore_updater import update_vectorstore, create_vectorstore -from langchain.document_loaders import DirectoryLoader -from langchain.text_splitter import CharacterTextSplitter -from langchain.text_splitter import RecursiveCharacterTextSplitter -from langchain.document_loaders import DirectoryLoader, UnstructuredFileLoader,Docx2txtLoader, UnstructuredHTMLLoader, TextLoader, UnstructuredPDFLoader +from langchain_text_splitters import CharacterTextSplitter, RecursiveCharacterTextSplitter +from langchain_community.document_loaders import DirectoryLoader, UnstructuredFileLoader, Docx2txtLoader, UnstructuredHTMLLoader, TextLoader, UnstructuredPDFLoader from langchain_nvidia_ai_endpoints import ChatNVIDIA, NVIDIAEmbeddings from langchain_core.output_parsers import StrOutputParser from langchain_community.embeddings import NeMoEmbeddings from langchain_core.prompts import ChatPromptTemplate -from continuous_eval.data_downloader import example_data_downloader -from continuous_eval.evaluators import RetrievalEvaluator, GenerationEvaluator from llm.llm import create_llm import re import pandas as pd @@ -39,10 +35,9 @@ import matplotlib.pyplot as plt from PIL import Image import yaml -from continuous_eval.metrics import PrecisionRecallF1, RankedRetrievalMetrics, DeterministicAnswerCorrectness, DeterministicFaithfulness, BertAnswerRelevance, BertAnswerSimilarity, DebertaAnswerScores from langchain_community.vectorstores import FAISS -llm_2 = ChatNVIDIA(model="playground_steerlm_llama_70b") +llm_2 = ChatNVIDIA(model="meta/llama3-70b-instruct") if yaml.safe_load(open('config.yaml', 'r'))['NREM']: # Embeddings with NeMo Retriever Embeddings Microservice (NREM) @@ -53,7 +48,7 @@ else: # Embeddings with NVIDIA AI Foundation Endpoints - nv_embedder = NVIDIAEmbeddings(model="ai-embed-qa-4") + nv_embedder = NVIDIAEmbeddings(model=yaml.safe_load(open('config.yaml', 'r'))['embedding_model']) prompt_template = ChatPromptTemplate.from_messages( @@ -205,7 +200,7 @@ def plot_metrics_with_values(metrics_dict, title='RAG Metrics',figsize=(10, 6)): }''' instruction_prompt = 'Given the previous paragraph, create one high quality question answer pair. The answer should be brief while covering technical depth, and must be restricted to the content provided. Your output should be a JSON formatted string with the question answer pair. Restrict the question to the context information provided.' system_prompt="You are an expert ORAN assistant at NVIDIA. You have a deep technical understanding of ORAN's specifications, standards and processes. Your job is to generate FAQs from documents for other colleagues to use in the field while informing about ORAN to customers." - llm = create_llm("mixtral_8x7b", "NVIDIA") + llm = create_llm("mistralai/mixtral-8x7b-instruct-v0.1", "NVIDIA") langchain_prompt = ChatPromptTemplate.from_messages([ ("system", system_prompt), ("human", "{sample_doc}\n{instruction_prompt}"), diff --git a/experimental/oran-chatbot-multimodal/requirements.txt b/experimental/oran-chatbot-multimodal/requirements.txt index 6976b66ac..87e4b6085 100644 --- a/experimental/oran-chatbot-multimodal/requirements.txt +++ b/experimental/oran-chatbot-multimodal/requirements.txt @@ -7,10 +7,11 @@ faiss-cpu fastapi==0.104.1 gspread==6.0.0 jupyterlab==4.0.8 -langchain==0.1.14 -langchain-community==0.0.31 -langchain-core==0.1.40 -langchain-nvidia-ai-endpoints==0.0.9 +langchain==0.2.5 +langchain-community==0.2.5 +langchain-core==0.2.7 +langchain-nvidia-ai-endpoints==0.1.1 +langchain-text-splitters==0.2.1 llama-hub==0.0.43 llama-index==0.9.22 opencv-python==4.8.0.74 @@ -30,4 +31,5 @@ streamlit_feedback==0.1.3 torch==2.1.2 transformers==4.35.2 unstructured[all-docs]==0.11.2 -uvicorn[standard]==0.24.0 \ No newline at end of file +uvicorn[standard]==0.24.0 +wheel \ No newline at end of file diff --git a/experimental/oran-chatbot-multimodal/retriever/retriever.py b/experimental/oran-chatbot-multimodal/retriever/retriever.py index 98f24ba9b..56f4e9ae2 100644 --- a/experimental/oran-chatbot-multimodal/retriever/retriever.py +++ b/experimental/oran-chatbot-multimodal/retriever/retriever.py @@ -29,6 +29,10 @@ from langchain_community.vectorstores import FAISS from langchain_community.embeddings import NeMoEmbeddings import yaml +import os + +NVIDIA_API_KEY = yaml.safe_load(open("config.yaml"))['nvidia_api_key'] +os.environ['NVIDIA_API_KEY'] = NVIDIA_API_KEY def clean_source(full_path): return os.path.basename(full_path) @@ -59,7 +63,7 @@ def get_relevant_docs(DOCS_DIR, text, limit=None): else: # Embeddings with NVIDIA AI Foundation Endpoints - nv_embedder = NVIDIAEmbeddings(model="ai-embed-qa-4") + nv_embedder = NVIDIAEmbeddings(model=yaml.safe_load(open('config.yaml', 'r'))['embedding_model']) vectorstore = FAISS.load_local(os.path.join(DOCS_DIR, "vectorstore_nv"), nv_embedder, allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_type="similarity_score_threshold", diff --git a/experimental/oran-chatbot-multimodal/vectorstore/vectorstore_updater.py b/experimental/oran-chatbot-multimodal/vectorstore/vectorstore_updater.py index 654a80c4f..f6ee59121 100644 --- a/experimental/oran-chatbot-multimodal/vectorstore/vectorstore_updater.py +++ b/experimental/oran-chatbot-multimodal/vectorstore/vectorstore_updater.py @@ -21,11 +21,10 @@ from vectorstore.custom_powerpoint_parser import process_ppt_file from vectorstore.custom_pdf_parser import get_pdf_documents -from langchain.embeddings import HuggingFaceEmbeddings -from langchain.document_loaders import DirectoryLoader, UnstructuredFileLoader,Docx2txtLoader, UnstructuredHTMLLoader, TextLoader, UnstructuredPDFLoader +from langchain_community.document_loaders import DirectoryLoader, UnstructuredFileLoader, Docx2txtLoader, UnstructuredHTMLLoader, TextLoader, UnstructuredPDFLoader from langchain_nvidia_ai_endpoints import ChatNVIDIA, NVIDIAEmbeddings from langchain_community.vectorstores import FAISS -from langchain_community.embeddings import NeMoEmbeddings +from langchain_community.embeddings import NeMoEmbeddings, HuggingFaceEmbeddings from qdrant_client import QdrantClient import multiprocessing import pickle @@ -35,6 +34,8 @@ CUSTOM_PROCESSING = True +NVIDIA_API_KEY = yaml.safe_load(open("config.yaml"))['nvidia_api_key'] +os.environ['NVIDIA_API_KEY'] = NVIDIA_API_KEY # Initialize the HuggingFaceEmbeddings object # hf_embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-en-v1.5") # sample_text = "This is a sample text." @@ -59,7 +60,7 @@ else: # Embeddings with NVIDIA AI Foundation Endpoints - nv_embedder = NVIDIAEmbeddings(model="ai-embed-qa-4") + nv_embedder = NVIDIAEmbeddings(model=yaml.safe_load(open('config.yaml', 'r'))['embedding_model']) def load_documents(folder, status=None): """Load documents from the specified folder.""" diff --git a/experimental/rag-developer-chatbot/Dockerfile.notebook b/experimental/rag-developer-chatbot/Dockerfile.notebook new file mode 100644 index 000000000..9cb034211 --- /dev/null +++ b/experimental/rag-developer-chatbot/Dockerfile.notebook @@ -0,0 +1,18 @@ +# Use a base image with Python +FROM python:3.10-slim + +# Set working directory +WORKDIR /app + +COPY ./notebooks/. . + +# Run pip dependencies +RUN pip3 install -r requirements.txt + +RUN apt-get update && apt-get install -y unzip wget + +# Expose port 8888 for JupyterLab +EXPOSE 8888 + +# Start JupyterLab when the container runs +CMD ["jupyter", "lab", "--allow-root", "--ip=0.0.0.0","--NotebookApp.token=''", "--port=8888"] diff --git a/experimental/rag-developer-chatbot/README.md b/experimental/rag-developer-chatbot/README.md new file mode 100644 index 000000000..fa25c37b3 --- /dev/null +++ b/experimental/rag-developer-chatbot/README.md @@ -0,0 +1,70 @@ +# Developer RAG Chatbot Notebook + +## Prerequisites +Before proceeding with this guide, make sure you meet the following prerequisites: + +- You should have at least one NVIDIA GPU. + + - NVIDIA driver version 535 or newer. To check the driver version run: ``nvidia-smi --query-gpu=driver_version --format=csv,noheader``. + - If you are running multiple GPUs they must all be set to the same mode (ie Compute vs. Display). You can check compute mode for each GPU using + ``nvidia-smi -q -d compute`` + +### Setup the following + +- Docker and Docker-Compose are essential. Please follow the [installation instructions](https://docs.docker.com/engine/install/ubuntu/). + + Note: + Please do **not** use Docker that is packaged with Ubuntu as the newer version of Docker is required for proper Docker Compose support. + + Make sure your user account is able to execute Docker commands. + + +- NVIDIA Container Toolkit is also required. Refer to the [installation instructions](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html). + + +- NGC Account and API Key + + - Please refer to [instructions](https://docs.nvidia.com/ngc/gpu-cloud/ngc-overview/index.html) to create an account + + Once your account has been created: + + * Navigate to https://build.nvidia.com/meta/llama3-70b?api-key=true + * Click "Get API Key" and follow the instructions to generate your API key + +- git-lfs + - Make sure you have [git-lfs](https://git-lfs.github.com) installed. + + +### Using Nvdia Cloud based LLM's + +#### Step 1: Sign up for an NGC Account to access the endpoint + +- Follow the above instructions to get access to an API key. + +#### Step 2: Set Environment Variables + +- Modify ``compose.env`` to set your environment variables. The following variable is required. + + export NVIDIA_API_KEY="nvapi-*" + + +#### Step 3: Build and Start Containers +- Pull lfs files. This will pull large files from repository. + ``` + git lfs pull + ``` +- Run the following command to build containers. + ``` + source experimental/developer-chatbot/compose.env; docker compose -f experimental/rag-developer-chatbot/docker-compose-dev-rag.yaml build + ``` + +- Run the following command to start containers. + ``` + source experimental/developer-chatbot/compose.env; docker compose -f experimental/rag-developer-chatbot/docker-compose-dev-rag.yaml up -d + ``` + > ⚠️ **NOTE**: It will take a few minutes for the containers to come up. Adding the `-d` flag will have the services run in the background. ⚠️ + +#### Step 4: Run the notebooks +The notebooks will run on a local JupyterServer on port 8888 (http://localhost:8888) + +[Developer RAG Chatbot](../../rapids/notebooks/rapids_notebook.ipynb) is the Developer RAG Chatbot notebook \ No newline at end of file diff --git a/experimental/rag-developer-chatbot/compose.env b/experimental/rag-developer-chatbot/compose.env new file mode 100644 index 000000000..929b33c6b --- /dev/null +++ b/experimental/rag-developer-chatbot/compose.env @@ -0,0 +1,71 @@ +# full path to the local copy of the model weights +# NOTE: This should be an absolute path and not relative path +export MODEL_DIRECTORY="/home/nvidia/llama2_13b_chat_hf_v1/" + +# the number of GPUs needed by nemollm inference ms to deploy the model +export NUM_GPU=1 + +# To control which GPU the vector database uses, specify the device ID. +# export VECTORSTORE_GPU_DEVICE_ID=0 + +# Fill this out if you dont have a GPU. Leave this empty if you have a local GPU +export NVIDIA_API_KEY=${NVIDIA_API_KEY} + +# flag to enable activation aware quantization for the LLM +# export QUANTIZATION="int4_awq" + +# the architecture of the model. eg: llama, gptnext (for nemotron use gptnext) +export MODEL_ARCHITECTURE="llama" + + +# the name of the model being used - only for displaying on rag-playground +# export MODEL_NAME="Llama-2-13b-chat-hf" + +# [OPTIONAL] the maximum number of input tokens +# export MODEL_MAX_INPUT_LENGTH=3000 + +# [OPTIONAL] the number of GPUs to make available to the inference server +# export INFERENCE_GPU_COUNT="all" + +# [OPTIONAL] the base directory inside which all persistent volumes will be created +# export DOCKER_VOLUME_DIRECTORY="." + +# full path to the model store directory storing the nemo embedding model +export EMBEDDING_MODEL_DIRECTORY="/home/nvidia/nv-embed-qa_v4" + +# name of the nemo embedding model +export EMBEDDING_MODEL_NAME="NV-Embed-QA" +export EMBEDDING_MODEL_CKPT_NAME="NV-Embed-QA-4.nemo" + +# GPU id which nemo embedding ms will use +# export EMBEDDING_MS_GPU_ID=0 + +# parameters for PGVector, update this when using PGVector Vector store +# export POSTGRES_PASSWORD=password +# export POSTGRES_USER=postgres +# export POSTGRES_DB=api + +# Update this line when using an external PGVector Vector store +# export POSTGRES_HOST_IP=pgvector +# export POSTGRES_PORT_NUMBER=5432 + +### Riva Parameters: + +# Riva Speech API URI: Riva Server IP address/hostname and port +export RIVA_API_URI="" + +# [OPTIONAL] Riva Speech API Key +# If necessary, enter a key to access the Riva API +export RIVA_API_KEY="" + +# [OPTIONAL] Riva Function ID +# If necessary, enter a function ID to access the Riva API +export RIVA_FUNCTION_ID="" + +# TTS sample rate (Hz) +export TTS_SAMPLE_RATE=48000 + +# the config file for the OpenTelemetry collector +export OPENTELEMETRY_CONFIG_FILE="./configs/otel-collector-config.yaml" +# the config file for Jaeger +export JAEGER_CONFIG_FILE="./configs/jaeger.yaml" diff --git a/experimental/rag-developer-chatbot/docker-compose-dev-rag.yaml b/experimental/rag-developer-chatbot/docker-compose-dev-rag.yaml new file mode 100644 index 000000000..ac0e92863 --- /dev/null +++ b/experimental/rag-developer-chatbot/docker-compose-dev-rag.yaml @@ -0,0 +1,27 @@ +services: + + jupyter-server: + container_name: notebook-server-dev-rag + image: notebook-server-dev-rag:latest + build: + context: . + dockerfile: Dockerfile.notebook + ports: + - "8888:8888" + - "7860:7860" + expose: + - "8888" + - "7860" + env_file: + - compose.env + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: 1 + capabilities: [gpu] + +networks: + default: + name: nvidia-llm diff --git a/experimental/rag-developer-chatbot/notebooks/diagram.png b/experimental/rag-developer-chatbot/notebooks/diagram.png new file mode 100644 index 000000000..377299802 Binary files /dev/null and b/experimental/rag-developer-chatbot/notebooks/diagram.png differ diff --git a/experimental/rag-developer-chatbot/notebooks/rapids_notebook.ipynb b/experimental/rag-developer-chatbot/notebooks/rapids_notebook.ipynb new file mode 100644 index 000000000..0d01317f5 --- /dev/null +++ b/experimental/rag-developer-chatbot/notebooks/rapids_notebook.ipynb @@ -0,0 +1,575 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4272a6e3-00e8-4c89-a345-50497b529390", + "metadata": {}, + "source": [ + "### Developer RAG Chatbot\n", + "\n", + "In this notebook, we are going to build a basic developer chatbot. The Developer RAG Chatbot is intended to provide an example RAG workflow for developers. This example uses RAPIDS cuDF source code and API documentation as a representative dataset of a developer's codebase. We will use this dataset to create a code chatbot/assistant that can answer questions about cuDF and provide examples of using the API. Note that the example is intended to make it easier for developers to interact and come up to speed with a code base, but not necessarily fully generate code for the developer.\n", + "\n", + "To build this application, we'll be using Llama3 70B hosted on NV AI Foundation as the LLM and the E5-Large embedding model. We'll add the embeddings into a FAISS vector database and use Langchain to build the logic tying the pieces together. Finally, we'll use Gradio as the interface for accessing the chatbot.\n", + "\n", + "![title](diagram.png)\n", + "\n", + "Prerequisites\n", + "\n", + "1. Setup your NVIDIA NGC account and generate an API Key: https://python.langchain.com/docs/integrations/chat/nvidia_ai_endpoints/#setup\n", + "2. An NVIDIA GPU with at least 4 GB of memory is required to run the embedding model and create the necessary vectorstores" + ] + }, + { + "cell_type": "markdown", + "id": "449d505b-2dca-4239-ac9c-bcacd6d7d1f2", + "metadata": {}, + "source": [ + "### Step 1: Pull cuDF Dataset\n", + "First, we pull the cuDf 24.04 release from GitHub." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4de388e-b4fe-4bb2-a75b-9f0fb14e6973", + "metadata": {}, + "outputs": [], + "source": [ + "!wget https://github.com/rapidsai/cudf/archive/refs/tags/v24.04.00.tar.gz\n", + "!tar -xzf v24.04.00.tar.gz" + ] + }, + { + "cell_type": "markdown", + "id": "1c9d911d-47ca-44a5-be3c-d8183a43fd7d", + "metadata": {}, + "source": [ + "### Step 2: Parse Source Code and Documentation\n", + "Next, we parse the relevant python source code and related documentation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43793ae9-f25f-4e9d-a7a5-13b64f02b115", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.document_loaders import DirectoryLoader, TextLoader, PythonLoader\n", + "import os\n", + "\n", + "CLONE_DIR = \"cudf-24.04.00\"\n", + "SOURCE_DIR = os.path.join(CLONE_DIR, \"python\", \"cudf\", \"cudf\")\n", + "SOURCE_DOC_DIR = os.path.join(CLONE_DIR, \"docs\", \"cudf\", \"source\", \"user_guide\")\n", + "\n", + "text_loader_kwargs={'autodetect_encoding': True}\n", + "\n", + "code_loader = DirectoryLoader(SOURCE_DIR, glob=\"**/*.py\", use_multithreading=True, loader_cls=PythonLoader)\n", + "code_data = code_loader.load()\n", + "print(\"Code files found: \" + str(len(code_data)))\n", + "\n", + "#delete index files to avoid irrelevant results\n", + "doc_index = os.path.join(SOURCE_DOC_DIR,\"index.md\")\n", + "api_doc_index = os.path.join(SOURCE_DOC_DIR,\"api_docs\",\"index.rst\")\n", + "if(os.path.isfile(doc_index)):\n", + " os.remove(doc_index)\n", + "if(os.path.isfile(api_doc_index)):\n", + " os.remove(api_doc_index)\n", + "\n", + "doc_loader = DirectoryLoader(SOURCE_DOC_DIR, glob=\"**/*.md\", use_multithreading=True, loader_cls=TextLoader)\n", + "doc_data = doc_loader.load()\n", + "doc_loader = DirectoryLoader(SOURCE_DOC_DIR, glob=\"**/*.ipynb\", use_multithreading=True, loader_cls=TextLoader)\n", + "doc_data = doc_data + doc_loader.load()\n", + "print(\"Documentation files found: \" + str(len(doc_data)))\n", + "\n", + "api_loader = DirectoryLoader(SOURCE_DOC_DIR, glob=\"**/*.rst\", use_multithreading=True, loader_cls=TextLoader)\n", + "api_data = api_loader.load()\n", + "print(\"API files found: \" + str(len(api_data)))" + ] + }, + { + "cell_type": "markdown", + "id": "8ba71a28-312d-47c5-a9a7-efa8c8878e5d", + "metadata": {}, + "source": [ + "### Step 3: Split Data to Prepare for Embedding\n", + "In this step, we split our data into smaller chunks for the embedding process.\n", + "\n", + "**Note: It may take several minutes for the e5-large-v2 model to download.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fea998e-c776-4763-b811-b42b6372fcb9", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "from langchain.text_splitter import (Language, SentenceTransformersTokenTextSplitter, RecursiveCharacterTextSplitter)\n", + "\n", + "TEXT_SPLITTER_MODEL = \"intfloat/e5-large-v2\"\n", + "TEXT_SPLITTER_CHUNK_SIZE = 512\n", + "TEXT_SPLITTER_CHUNK_OVERLAP = 256\n", + "\n", + "text_splitter = SentenceTransformersTokenTextSplitter(\n", + " model_name=TEXT_SPLITTER_MODEL,\n", + " chunk_size=TEXT_SPLITTER_CHUNK_SIZE,\n", + " chunk_overlap=TEXT_SPLITTER_CHUNK_OVERLAP,\n", + ")\n", + "\n", + "python_splitter = RecursiveCharacterTextSplitter.from_language(\n", + " language=Language.PYTHON, chunk_size=512, chunk_overlap=256)\n", + "\n", + "start_time = time.time()\n", + "\n", + "code_docs = python_splitter.split_documents(code_data)\n", + "\n", + "documents = text_splitter.split_documents(doc_data)\n", + "\n", + "api_docs= text_splitter.split_documents(api_data)\n", + "\n", + "print(f\"--- {time.time() - start_time} seconds ---\")" + ] + }, + { + "cell_type": "markdown", + "id": "c72a07ff-119a-468c-ab68-f8f6e9f7c6fc", + "metadata": {}, + "source": [ + "### Step 4: Generate Embeddings and Store Embeddings in the Vector Store \n", + "Next, we generate our embeddings from our dataset, and store them in the appropriate vector stores.\n", + "This process will generally take several minutes, depending on your hardware.\n", + "A cached version of each vector store will be saved locally for use in future notebook runs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ee3be33-5f78-4937-9e07-a7cc93d5d7df", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.embeddings import HuggingFaceEmbeddings\n", + "from langchain_community.vectorstores import FAISS\n", + "import time\n", + "import os\n", + "\n", + "start_time = time.time()\n", + "\n", + "#load embeddings model\n", + "model_name = \"intfloat/e5-large-v2\"\n", + "model_kwargs = {\"device\": \"cuda\"}\n", + "encode_kwargs = {\"normalize_embeddings\": False}\n", + "embeddings = HuggingFaceEmbeddings(\n", + " model_name=model_name,\n", + " model_kwargs=model_kwargs,\n", + " encode_kwargs=encode_kwargs,\n", + " show_progress=True\n", + ")\n", + "\n", + "vectorstore_docs_path = \"doc_index\"\n", + "vectorstore_code_path = \"code_index\"\n", + "vectorstore_api_path = \"api_index\"\n", + "\n", + "vectorstore_doc = None\n", + "vectorstore_code = None\n", + "vectorstore_api = None\n", + "\n", + "\n", + "\n", + "#load or create individual vectorstores as appropriate\n", + "\n", + "if os.path.exists(vectorstore_docs_path):\n", + " #load doc vectorstores\n", + " vectorstore_doc = FAISS.load_local(vectorstore_docs_path, embeddings, allow_dangerous_deserialization=True)\n", + "else:\n", + " #run to create doc vectorstore\n", + " vectorstore_doc = FAISS.from_documents(documents, embeddings)\n", + " vectorstore_doc.save_local(vectorstore_docs_path)\n", + "\n", + "if os.path.exists(vectorstore_code_path):\n", + " #load code vectorstore\n", + " vectorstore_code = FAISS.load_local(vectorstore_code_path, embeddings, allow_dangerous_deserialization=True)\n", + "else:\n", + " # create code vectorestore\n", + " vectorstore_code = FAISS.from_documents(code_docs, embeddings)\n", + " vectorstore_code.save_local(vectorstore_code_path)\n", + "\n", + "if os.path.exists(vectorstore_api_path):\n", + " #load api vectorstore\n", + " vectorstore_api = FAISS.load_local(vectorstore_api_path, embeddings,allow_dangerous_deserialization=True)\n", + "else:\n", + " #create api vectorstore\n", + " vectorstore_api = FAISS.from_documents(api_docs, embeddings)\n", + " vectorstore_api.save_local(vectorstore_api_path)\n" + ] + }, + { + "cell_type": "markdown", + "id": "bc71d0c9-aeab-4a26-959f-5493ca1f2f02", + "metadata": {}, + "source": [ + "### Step 5: Test Embeddings\n", + "Here we pass in a simple test query to ensure we are pulling relevant chunks from our code vector store. Notice it should include the 'size' function definition from the frame.py script as part of the retrieved context." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7998432-e6d2-4da8-8781-798f43835d19", + "metadata": {}, + "outputs": [], + "source": [ + "retriever_docs = vectorstore_code.as_retriever(search_kwargs= {\"k\":3})\n", + "\n", + "test_docs = retriever_docs.get_relevant_documents(\"How can I check the size of my dataframe?\")\n", + "\n", + "for doc in test_docs:\n", + " print(doc, end=\"\\n\")\n", + " print(\"\\n\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "026b7e51-6029-4fc4-ba16-905e49946308", + "metadata": {}, + "source": [ + "### Step 6: Connect to LLM\n", + "Here we create the connection to the Llama3-70b model via the NVIDIA AI Foundation Endpoint." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cddceb0-1f58-48c4-aba4-cc1962ed8806", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_nvidia_ai_endpoints import ChatNVIDIA\n", + "import getpass\n", + "\n", + "#if you haven't already passed in your NVIDIA API KEY in the docker file, you can enter it manually here\n", + "if not os.environ.get(\"NVIDIA_API_KEY\", \"\").startswith(\"nvapi-\"):\n", + " nvapi_key = getpass.getpass(\"Enter your NVIDIA API key: \")\n", + " assert nvapi_key.startswith(\"nvapi-\"), f\"{nvapi_key[:5]}... is not a valid key\"\n", + " os.environ[\"NVIDIA_API_KEY\"] = nvapi_key\n", + "\n", + "#Try using the llama3-8b-instruct model to see how results can differ!\n", + "llm = ChatNVIDIA(\n", + " temperature=0.01,\n", + " max_tokens=1024,\n", + " model=\"meta/llama3-70b-instruct\",\n", + " stream= True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "225fc935-4bc9-4957-a476-6d23d147e664", + "metadata": {}, + "source": [ + "### Step 7: Create prompt pipeline\n", + "Next we create the prompt for our chatbot. We've broken it into several pieces to make it easier to understand the individual portions of the prompt. We bring the individual pieces of the prompt together using a pipeline prompt at the end of the section." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c6c95bf-3a18-4d76-9625-bf28b08fc1a9", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.prompts.pipeline import PipelinePromptTemplate\n", + "from langchain.prompts import PromptTemplate\n", + "\n", + "#Llama3 Prompt template\n", + "full_template = \"\"\" [INST] <>\n", + "{introduction}\n", + "{example}\n", + "<>\n", + "|\n", + "{start} [/INST]\"\"\"\n", + "\n", + "full_prompt = PromptTemplate.from_template(full_template)\n", + "\n", + "introduction_template = \"\"\" You are an expert on the RAPIDs cuDF framework. Only provide answers around cuDF functionality. Don't return answers for topics that aren't related to cuDF. If you don't know the answer, just say that you don't know, don't try to make up an answer.\"\"\"\n", + "introduction_prompt = PromptTemplate.from_template(introduction_template)\n", + "\n", + "example_template = \"\"\"Here's an example of an interaction:\n", + "\n", + "Question: {example_q}\n", + "Answer: {example_a}\n", + "\n", + "Use the following context to answer the user's question. Context: {context} Chat History: {history} Only return the helpful answer below and nothing else. Don't make up functions, variables, or properties. Only include functions, variables, or properties for which you have a source. Provide only a single, best example when answering the question.\"\"\"\n", + "example_prompt = PromptTemplate.from_template(example_template)\n", + "\n", + "start_template = \"\"\" Assume the user is asking about the Python implementation. Don't provide an answer if it's unrelated to cuDF. Question: {question} Answer:\"\"\"\n", + "start_prompt = PromptTemplate.from_template(start_template)\n", + "\n", + "input_prompts = [\n", + " (\"introduction\", introduction_prompt),\n", + " (\"example\", example_prompt),\n", + " (\"start\", start_prompt),\n", + "]\n", + "pipeline_prompt = PipelinePromptTemplate(\n", + " final_prompt=full_prompt, pipeline_prompts=input_prompts\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e97ad763-1714-47d3-8cc8-e62e95775cae", + "metadata": {}, + "source": [ + "### Step 8: Create Retrievers\n", + "In this section, we create retrievers to access the data in our vector stores. We add additional parameters and filtering to ensure only the most relevant documents are returned." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a98be643-46b4-4cd2-825a-4cdaafa2c418", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.retrievers.merger_retriever import MergerRetriever\n", + "from langchain.retrievers import ContextualCompressionRetriever\n", + "from langchain.retrievers.document_compressors import DocumentCompressorPipeline\n", + "from langchain.retrievers.document_compressors import EmbeddingsFilter\n", + "\n", + "#create merger retriever to combine results from multiple vectorstores\n", + "merger_retriever = MergerRetriever(retrievers=[])\n", + "retriever_code = vectorstore_code.as_retriever(search_type = \"similarity_score_threshold\", search_kwargs= {\"k\":4, \"score_threshold\": 0.75})\n", + "retriever_docs = vectorstore_doc.as_retriever(search_type = \"similarity_score_threshold\", search_kwargs= {\"k\":4, \"score_threshold\": 0.7})\n", + "retriever_api = vectorstore_api.as_retriever(search_type = \"similarity_score_threshold\", search_kwargs= {\"k\":4, \"score_threshold\": 0.7})\n", + "\n", + "filter_ordered_by_retriever = EmbeddingsFilter(embeddings=embeddings, k = 5, sorted = True)\n", + "\n", + "pipeline = DocumentCompressorPipeline(transformers=[filter_ordered_by_retriever])\n", + "compression_retriever = ContextualCompressionRetriever(\n", + " base_compressor=pipeline, base_retriever=merger_retriever)\n", + "\n", + "#update merger_retriever based on selected vectorstores\n", + "def update_retriever(kb_code, kb_docs, kb_api, merger_retriever):\n", + " retrievers = []\n", + "\n", + " if kb_code:\n", + " retrievers.append(retriever_code)\n", + " if kb_docs:\n", + " retrievers.append(retriever_docs)\n", + " if kb_api:\n", + " retrievers.append(retriever_api)\n", + "\n", + " merger_retriever.retrievers = retrievers" + ] + }, + { + "cell_type": "markdown", + "id": "704480ed-8af7-42e0-a14f-345328a5533f", + "metadata": {}, + "source": [ + "### Step 9: Implement Chatbot Logic\n", + "In this section, we implement the main logic for our chatbot. This includes the chatbot response function, managing the size of the chat history, and adding sources to the response." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd381232-b5a7-4691-a2ea-ca252d4a1328", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.output_parsers import StrOutputParser\n", + "from langchain_core.runnables import RunnablePassthrough, RunnableParallel, RunnableLambda\n", + "import gradio as gr\n", + "import re\n", + "\n", + "welcome_message = [(None, \"Hello! I'm your cuDF Assistant! How can I help you?\")]\n", + "\n", + "example_questions = [[\"How do I check the size of a data frame?\"],\n", + " [\"What are the main differences between the cuDF and pandas APIs?\"],\n", + " [\"What is the default data type value returned inside a dataframe when calling get_dummies?\"],\n", + " [\"Is output order guaranteed when using the join function?\"] ]\n", + "\n", + "def choose_chat_response(message, history, knowledge_base):\n", + " if not message or message.isspace():\n", + " yield \"Please enter a question.\"\n", + " else:\n", + " kb_docs = True if 0 in knowledge_base else False\n", + " kb_api = True if 1 in knowledge_base else False\n", + " kb_code = True if 2 in knowledge_base else False\n", + "\n", + " use_kb = False\n", + " #if any knowledge bases selected, use RAG pipeline\n", + " if kb_code or kb_docs or kb_api:\n", + " update_retriever(kb_code, kb_docs, kb_api, merger_retriever)\n", + " use_kb = True\n", + " yield from chat_response(message, history, use_kb)\n", + "\n", + "#reset chat history\n", + "def reset(z):\n", + " return welcome_message, []\n", + "\n", + "def format_docs(docs):\n", + " return \"\\n\\n\".join(doc.page_content for doc in docs)\n", + "\n", + "def limit_chat_history(chat_history, char_limit):\n", + " total_chars = sum( 0 if user is None else len(user) + 0 if bot is None else len(bot) for user, bot in chat_history)\n", + " while total_chars > char_limit:\n", + " # Remove the oldest message pair\n", + " removed_user, removed_bot = chat_history.pop(0)\n", + " total_chars -= (0 if removed_user is None else len(removed_user) + len(removed_bot))\n", + "\n", + " history_text = \"\"\n", + " #go through history and add each q+a pair\n", + " for qa_pair in chat_history:\n", + " q = qa_pair[0]\n", + " a = qa_pair[1]\n", + "\n", + " #initial user input is None due to initialization value\n", + " if q is not None:\n", + " history_text+= (\"user: \" + q + \"\\n\")\n", + " #only pass along the response without sources so the LLM doesn't learn to include them automatically\n", + " history_text+=(\"response: \" + a.split(\"Sources:\")[0] + \"\\n\")\n", + "\n", + " return history_text\n", + "\n", + "#get sources from doc metadata and format appropriately\n", + "def get_sources(docs):\n", + " try:\n", + " sources=[]\n", + " for doc in docs:\n", + " metadata = doc.metadata\n", + " source = metadata['source']\n", + "\n", + " if source.endswith('.md') or source.endswith('.ipynb') or source.endswith('.rst'):\n", + " url_start = \"https://docs.rapids.ai/api/cudf/stable\"\n", + " source = source.replace('cudf-24.04.00/docs/cudf/source', url_start)\n", + " source = source.replace('.md','')\n", + " source = source.replace('.ipynb','')\n", + " source = source.replace('.rst','')\n", + "\n", + " elif source.endswith('.py'):\n", + " url_start = \"https://github.com/rapidsai/cudf/blob/branch-24.04/python/cudf\"\n", + " source = source.replace('cudf-24.04.00/python/cudf',url_start)\n", + "\n", + " if source not in sources:\n", + " sources.append(source)\n", + " if(len(sources) == 0):\n", + " sources.append(\"No relevant sources found within the selected knowledge bases.\")\n", + " return sources\n", + " except:\n", + " print(\"source parse error\")\n", + "\n", + "def chat_response(message, history, use_kb):\n", + "\n", + " #prompt is currently around ~1500 chars\n", + " #context is ~500x5 = ~2500 chars\n", + " #Llama3 context limit 8k\n", + " #limiting history to 4k chars for now\n", + " history_text = limit_chat_history(history,4000)\n", + "\n", + " formatted_context = None\n", + " if use_kb:\n", + " context = compression_retriever.get_relevant_documents(message)\n", + " formatted_context = format_docs(context)\n", + "\n", + " build_prompt = pipeline_prompt.format_prompt( context= formatted_context, example_q = \"How can I check what's in the first row of my dataframe?\", example_a = \"\"\"You can check what's in the first row of your dataframe by using the head() function. For example:\n", + "\n", + "import cuDF\n", + "\n", + "# create a sample dataframe\n", + "df = cuDF.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})\n", + "\n", + "# print the first row of the dataframe\n", + "print(df.head(1))\n", + "\n", + "This will output the first row of the dataframe, which in this case is:\n", + "\n", + " A B\n", + "0 1 4 \"\"\", question = message, history= history_text)\n", + "\n", + " llm_chain = (\n", + " llm\n", + " | StrOutputParser()\n", + " )\n", + "\n", + " result = \"\"\n", + " for txt in llm_chain.stream(build_prompt):\n", + " result += txt\n", + " yield result\n", + "\n", + " if use_kb:\n", + " sources = get_sources(context)\n", + " ranked_list = [f\"{index+1}: {value}\" for index, value in enumerate(sources)]\n", + " result = result +\"\\n\\nSources:\\n\" + \"\\n\".join(ranked_list)\n", + "\n", + " yield result" + ] + }, + { + "cell_type": "markdown", + "id": "14b1a3ad-a2da-4d3f-acb4-3d0bfe9d5028", + "metadata": {}, + "source": [ + "### Step 10: Start Chatbot\n", + "We're finally ready to start our chatbot. Run the cell below to create the Gradio interface and begin interacting with your chatbot!\n", + "Note the differences in the responses when enabling the various knowledge bases, and compare that to the same response without using any knowledge bases." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcbf4ba3-a056-45ef-a7a0-c84114371465", + "metadata": {}, + "outputs": [], + "source": [ + "#You may need to explicitly hit the STOP button and try to relaunch your gradio interface when re-running this cell. This is a known Jupyter Notebook environment issue.\n", + "chatbot = gr.Chatbot(value = welcome_message)\n", + "with gr.Blocks() as demo:\n", + " knowledge_base = gr.CheckboxGroup(label = \"Knowledge Base Sources\", info= \"Choose which sources to use\",choices=[\"Docs\", \"API Docs\", 'Source Code',], type='index', value=['Docs', 'API Docs','Source Code'], render=False)\n", + " input_box = gr.Textbox(value = \"How do I check the size of a data frame?\", scale=4, render = False)\n", + " chat = gr.ChatInterface(choose_chat_response,\n", + " additional_inputs_accordion = gr.Accordion(open=True, label = \"Options\", render=False),\n", + " additional_inputs=[knowledge_base],\n", + " examples = example_questions,\n", + " textbox = input_box,\n", + " title = \"cuDF RAG Chatbot\",\n", + " chatbot=chatbot,\n", + " concurrency_limit=1)\n", + " #need to reset chat history when checkbox clicked so that the chatbot doesn't have potential answers from previous time question was asked\n", + " knowledge_base.input(fn=reset, inputs=knowledge_base, outputs=[chatbot, chat.chatbot_state])\n", + "\n", + "try:\n", + " demo.launch(server_name=\"0.0.0.0\", debug=True, show_api=False)\n", + " demo.close()\n", + "except Exception as e:\n", + " demo.close()\n", + " print(e)\n", + " raise e" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/experimental/rag-developer-chatbot/notebooks/requirements.txt b/experimental/rag-developer-chatbot/notebooks/requirements.txt new file mode 100644 index 000000000..52ed6861d --- /dev/null +++ b/experimental/rag-developer-chatbot/notebooks/requirements.txt @@ -0,0 +1,7 @@ +langchain==0.2.1 +langchain-community==0.2.1 +sentence-transformers==2.2.2 +jupyterlab==4.0.8 +langchain-nvidia-ai-endpoints==0.0.20 +gradio==4.16.0 +faiss-gpu==1.7.2 \ No newline at end of file diff --git a/integrations/langchain/__init__.py b/integrations/langchain/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/integrations/langchain/embeddings/__init__.py b/integrations/langchain/embeddings/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/integrations/langchain/embeddings/nemo_embed.py b/integrations/langchain/embeddings/nemo_embed.py deleted file mode 100644 index a8c0320b5..000000000 --- a/integrations/langchain/embeddings/nemo_embed.py +++ /dev/null @@ -1,102 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Nemo Embedding Microservice""" - -import requests -import json -import logging -from typing import Any, List, Sequence, Optional - -from langchain.pydantic_v1 import BaseModel -from langchain.schema.embeddings import Embeddings - -logger = logging.getLogger(__name__) - -class NemoEmbeddings(BaseModel, Embeddings): - """A custom Langchain Embedding class that integrates with Nemo Embedding MS - - Arguments: - server_url: (str) The URL of the Nemo Embedding MS to use. - model_name: (str) The name of the Nemo Embedding MS model to use. - """ - server_url: str = "http://localhost:9080/v1/embeddings" - model_name: str = "NV-Embed-QA-003" - - def __init__(self, *args: Sequence, **kwargs: Any): - super().__init__(*args, **kwargs) - - def _embed( - self, - query: Optional[str] = "", - input_type: Optional[str] = "query", - request_timeout: Optional[int] = 5, - **kwargs, - ) -> List[float]: - """ Function to get the embeddings from Nemo MS using REST API""" - - headers = {"accept": "application/json", "Content-Type": "application/json"} - data = {} - if query: - data["input"] = query - - if not data["input"]: - logger.warning("Valid query/passage not found in request") - return [] - - if self.model_name: - data["model"] = self.model_name - - if input_type: - data["input_type"] = input_type - - data["encoding_format"] = "float" - data["truncate"] = "END" - - response = None - request_timeout = int(request_timeout) - - if self.server_url is None: - logger.warning( - "Nemo Embedding Microservice URL not provided" - ) - return [] - - try: - response = requests.post(self.server_url, headers=headers, data=json.dumps(data), timeout=request_timeout) - response.raise_for_status() - except requests.exceptions.Timeout: - logger.info("Http request to Nemo Embedding Microservice timed out.") - except requests.exceptions.RequestException as e: - logger.info(f"An error occurred in Http request to Nemo Embedding Microservice endpoint {str(e)}") - - if response and response.json(): - response_data = response.json().get("data", {}) - if len(response_data): - return response_data[0].get("embedding", []) - else: - return [] - - else: - logger.info(f"Invalid or empty response returned by the Nemo Embedding Microservice endpoint {response}") - return [] - - def embed_query(self, text: str) -> List[float]: - """Input pathway for query embeddings.""" - return self._embed(query=text, input_type="query") - - def embed_documents(self, texts: List[str]) -> List[List[float]]: - """Input pathway for document embeddings.""" - return [self._embed(query=text, input_type="passage") for text in texts] \ No newline at end of file diff --git a/integrations/langchain/embeddings/nv_aiplay.py b/integrations/langchain/embeddings/nv_aiplay.py deleted file mode 100644 index a3eacee7a..000000000 --- a/integrations/langchain/embeddings/nv_aiplay.py +++ /dev/null @@ -1,75 +0,0 @@ -"""Chat Model Components Derived from ChatModel/NVAIPlay""" - -import asyncio -from collections import abc -from typing import Any, List, Literal, Sequence - -from langchain_nvidia_ai_endpoints import ClientModel, NVCRModel -from langchain.pydantic_v1 import Field -from langchain.schema.embeddings import Embeddings - - -class NVAIPlayEmbeddings(ClientModel, Embeddings): - """NVIDIA's AI Playground NVOLVE Question-Answer Asymmetric Model.""" - - client: NVCRModel = Field(NVCRModel) - model: str = Field("nvolveqa") - max_length: int = Field(2048, ge=1, le=2048) - - def __init__(self, *args: Sequence, **kwargs: Any): - if "client" not in kwargs: - kwargs["client"] = NVCRModel(**kwargs) - super().__init__(*args, **kwargs) - - def _embed(self, text: str, model_type: Literal["passage", "query"]) -> List[float]: - """Embed a single text entry to either passage or query type""" - if len(text) > self.max_length: - text = text[: self.max_length] - output = self.client.get_req_generation( - model_name=self.model, - payload={ - "input": text, - "model": model_type, - "encoding_format": "float", - }, - ) - return output.get("embedding", []) - - def embed_query(self, text: str) -> List[float]: - """Input pathway for query embeddings.""" - return self._embed(text, model_type="query") - - def embed_documents(self, texts: List[str]) -> List[List[float]]: - """Input pathway for document embeddings.""" - return [self._embed(text, model_type="passage") for text in texts] - - async def aembed_batch_queries( - self, - texts: List[str], - max_concurrency: int = 10, - ) -> List[List[float]]: - """Embed search queries with Asynchronous Batching and Concurrency Control.""" - semaphore = asyncio.Semaphore(max_concurrency) - - async def embed_with_semaphore(text: str) -> abc.Coroutine: - async with semaphore: - return await self.aembed_query(text) - - tasks = [embed_with_semaphore(text) for text in texts] - return await asyncio.gather(*tasks) - - async def aembed_batch_documents( - self, - texts: List[str], - max_concurrency: int = 10, - ) -> List[List[float]]: - """Embed search docs with Asynchronous Batching and Concurrency Control.""" - semaphore = asyncio.Semaphore(max_concurrency) - - async def embed_with_semaphore(text: str) -> abc.Coroutine: - async with semaphore: - return await self.aembed_documents([text]) - - tasks = [embed_with_semaphore(text) for text in texts] - outs = await asyncio.gather(*tasks) - return [out[0] for out in outs] diff --git a/integrations/langchain/llms/__init__.py b/integrations/langchain/llms/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/integrations/langchain/llms/nemo_infer.py b/integrations/langchain/llms/nemo_infer.py deleted file mode 100644 index 299db18f8..000000000 --- a/integrations/langchain/llms/nemo_infer.py +++ /dev/null @@ -1,157 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -from functools import partial -from typing import Any, Callable, Dict, List, Optional - -import requests -from langchain.callbacks.manager import CallbackManagerForLLMRun -from langchain.llms.base import LLM - - -class NemoInfer(LLM): - """A custom Langchain LLM class that integrates with NemoInfer MS. - - Arguments: - server_url: (str) The URL of the NemoInfer MS to use. - model_name: (str) The name of the NemoInfer MS model to use. - temperature: (str) Temperature to use for sampling - top_p: (float) The top-p value to use for sampling - stop: (List[str]) The words indicate stop generation of response - frequency_penalty: (float): penalty to each token that appears more frequently - streaming: (bool): Stream response - tokens: (int) The maximum number of tokens to generate. - """ - model: str = "llama" - temperature: Optional[float] = 1 - stop: Optional[List[str]] = ["", ""] - n: Optional[int] = 1 - top_p: Optional[float] = 0.01 - frequency_penalty: Optional[float] = 0 - server_url: Optional[str] = "http://localhost:9999" - streaming: Optional[bool] = True - tokens: Optional[int] = 50 # This corresponds with max_tokens in openai schema - - @property - def _llm_type(self) -> str: - return "NemoInfer" - - @property - def _default_params(self) -> Dict[str, Any]: - """Get the default parameters for calling NemoInfer MS API.""" - - normal_params: Dict[str, Any] = { - "frequency_penalty": self.frequency_penalty, - "n": self.n, - "model": self.model, - "max_tokens": self.tokens, - "stream": self.streaming - } - - # Either temperature or top_p should be set not both - if self.temperature: - normal_params["temperature"] = self.temperature - elif self.top_p: - normal_params["top_p"] = self.top_p - - return {**normal_params} - - def _stream_response_to_generation_chunk(self, chunk): - """parse json response from nemo ms api - """ - try: - chunk = json.loads(chunk) - chunk = chunk.get("choices", [{}])[0].get("text", "") - return chunk - except Exception as e: - return "" - - def _call( - self, - prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> str: - """ - Execute an inference request. - - Args: - prompt: The prompt to pass into the model. - stop: A list of strings to stop generation when encountered - - Returns: - The string generated by the model - """ - - text_callback = None - # Register text_callback for streaming response - if run_manager: - text_callback = partial(run_manager.on_llm_new_token, verbose=self.verbose) - - if stop is None: - stop = self.stop - - # Request to Nemo Infer MS - data = {"prompt": prompt, "stop": stop, **self._default_params} - # Nemo MS uses max_tokens instead of token - if "tokens" in kwargs: - data["max_tokens"] = kwargs.get("tokens") - - if self.streaming: - return self._streaming_request( - data, text_callback, **kwargs - ) - try: - response = requests.post(self.server_url, json=data) - resp = response.json() - resp = resp.get("choices", [{}])[0].get("text", "") - return resp - except Exception as e: - print(f"Exception: {e} while generating response") - return "" - - def _streaming_request( - self, - data: Dict[str, Any], - text_callback: Optional[Callable[[str], None]] = None, - **kwargs: Any, - ) -> str: - """parse streaming response from nemo ms api - """ - response = requests.post(self.server_url, json=data, stream=True) - current_string = "" - resp = "" - - # Check the response status - if response.status_code == 200: - for chunk in response.iter_lines(): - chunk = chunk.decode("utf-8") - if chunk: - # data: is appended before every chunk, remove it to parse json - chunk = chunk.lstrip("data: ") - chunk = self._stream_response_to_generation_chunk(chunk) - # Unlike openai ms returns complete response instead of token - # find new generated chunk and send it for streaming - resp = chunk[len(current_string) :] - - # Nemo Infer MS sends stop words along response - if resp in data.get("stop", self.stop): - continue - if text_callback: - text_callback(resp) - current_string = chunk - return resp \ No newline at end of file diff --git a/integrations/langchain/llms/nv_aiplay.py b/integrations/langchain/llms/nv_aiplay.py deleted file mode 100644 index baafb49f5..000000000 --- a/integrations/langchain/llms/nv_aiplay.py +++ /dev/null @@ -1,759 +0,0 @@ -## NOTE: This class is intentionally implemented to subclass either ChatModel or LLM for -## demonstrative purposes and to make it function as a simple standalone file. - -from __future__ import annotations - -import asyncio -import json -import logging -import re -from typing import ( - Any, - AsyncIterator, - Callable, - Dict, - Generator, - Iterator, - List, - Optional, - Sequence, - Tuple, - Union, -) - -import aiohttp -import requests -from requests.models import Response - -from langchain.callbacks.manager import ( - AsyncCallbackManager, - AsyncCallbackManagerForLLMRun, - CallbackManager, -) -from langchain.llms.base import LLM -from langchain.pydantic_v1 import BaseModel, Field, SecretStr, root_validator -from langchain.schema.messages import BaseMessage, ChatMessageChunk -from langchain.schema.output import ChatGenerationChunk, GenerationChunk -from langchain.utils import get_from_dict_or_env - -logger = logging.getLogger(__name__) - - -class ClientModel(BaseModel): - """ - Custom BaseModel subclass with some desirable properties for subclassing - """ - - saved_parent: Optional[ClientModel] = None - - def __init__(self, *args: Sequence, **kwargs: Any[str, Any]): - super().__init__(*args, **kwargs) - - def subscope(self, *args: Sequence, **kwargs: Any) -> Any: - """Create a new ClientModel with the same values but new arguments""" - named_args = dict({k: v for k, v in zip(getattr(self, "arg_keys", []), args)}) - named_args = {**named_args, **kwargs} - out = self.copy(update=named_args) - out.validate(dict(out._iter(to_dict=False, by_alias=False, exclude_unset=True))) - for k, v in self.__dict__.items(): - if isinstance(v, ClientModel): - setattr(out, k, v.subscope(*args, **kwargs)) - out.saved_parent = self - return out - - def dict(self, *args: Sequence, **kwargs: Any) -> dict: - """Handle saved_parent bleeding into dict""" - out = super().dict(*args, **kwargs) - if "saved_parent" in out: - out.pop("saved_parent") - return out - - def get(self, key: str) -> Any: - """Get a value from the ClientModel, using it like a dictionary""" - return getattr(self, key) - - def transfer_state(self, other: Optional[ClientModel]) -> None: - """Transfer state from one ClientModel to another""" - if other is None: - return - for k, v in self.__dict__.items(): - if k in getattr(self, "state_vars", []): - setattr(other, k, v) - elif hasattr(v, "transfer_state"): - other_sub = getattr(other, k, None) - if other_sub is not None: - v.transfer_state(other_sub) - - @staticmethod - def desecretize(v: Any) -> Any: - """Desecretize a collection of values""" - recurse = ClientModel.desecretize - if isinstance(v, SecretStr): - return v.get_secret_value() - if isinstance(v, str): - return v - if isinstance(v, dict): - return {k: recurse(v) for k, v in v.items()} - if isinstance(v, list): - return [recurse(subv) for subv in v] - if isinstance(v, tuple): - return tuple(recurse(subv) for subv in v) - return v - - def __enter__(self) -> ClientModel: - return self - - def __exit__(self, type: Any, value: Any, traceback: Any) -> None: - self.transfer_state(self.saved_parent) - self.saved_parent = None - - -class NVCRModel(ClientModel): - - """ - Underlying Client for interacting with the AI Playground API. - Leveraged by the NVAIPlayBaseModel to provide a simple requests-oriented interface. - Direct abstraction over NGC-recommended streaming/non-streaming Python solutions. - - NOTE: AI Playground does not currently support raw text continuation. - """ - - ## Core defaults. These probably should not be changed - fetch_url_format: str = Field("https://api.nvcf.nvidia.com/v2/nvcf/pexec/status/") - call_invoke_base: str = Field("https://api.nvcf.nvidia.com/v2/nvcf/pexec/functions") - get_session_fn: Callable = Field(requests.Session) - get_asession_fn: Callable = Field(aiohttp.ClientSession) - - ## Populated on construction/validation - nvapi_key: Optional[SecretStr] - is_staging: Optional[bool] - available_models: Optional[Dict[str, str]] - - ## Generation arguments - max_tries: int = Field(5, ge=1) - stop: Union[str, List[str]] = Field([]) - headers = dict( - call={"Authorization": "Bearer {nvapi_key}", "Accept": "application/json"}, - stream={ - "Authorization": "Bearer {nvapi_key}", - "Accept": "text/event-stream", - "content-type": "application/json", - }, - ) - - ## Status Tracking Variables. Updated Progressively - last_inputs: Optional[dict] = Field(None) - last_response: Optional[Any] = Field(None) - last_msg: dict = Field({}) - available_functions: List[dict] = Field([{}]) - state_vars: Sequence[str] = Field( - [ - "last_inputs", - "last_response", - "last_msg", - "available_functions", - ] - ) - - @root_validator() - def validate_model(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Validate and update model arguments, including API key and formatting""" - values["nvapi_key"] = get_from_dict_or_env(values, "nvapi_key", "NVAPI_KEY") - if "nvapi-" not in values.get("nvapi_key", ""): - raise ValueError("Invalid NVAPI key detected. Should start with `nvapi-`") - values["is_staging"] = "nvapi-stg-" in values["nvapi_key"] - for header in values["headers"].values(): - if "{nvapi_key}" in header["Authorization"]: - nvapi_key = ClientModel.desecretize(values["nvapi_key"]) - header["Authorization"] = SecretStr( - header["Authorization"].format(nvapi_key=nvapi_key), - ) - if isinstance(values["stop"], str): - values["stop"] = [values["stop"]] - return values - - def __init__(self, *args: Sequence, **kwargs: Any): - """Useful to define custom operations on construction after validation""" - super().__init__(*args, **kwargs) - self.fetch_url_format = self._stagify(self.fetch_url_format) - self.call_invoke_base = self._stagify(self.call_invoke_base) - try: - self.available_models = self.get_available_models() - except Exception as e: - raise Exception("Error retrieving model list. Verify your NVAPI key") from e - - def _stagify(self, path: str) -> str: - """Helper method to switch between staging and production endpoints""" - if self.is_staging and "stg.api" not in path: - return path.replace("api", "stg.api") - if not self.is_staging and "stg.api" in path: - return path.replace("stg.api", "api") - return path - - #################################################################################### - ## Core utilities for posting and getting from NVCR - - def _post(self, invoke_url: str, payload: dict = {}) -> Tuple[Response, Any]: - """Method for posting to the AI Playground API.""" - self.last_inputs = dict( - url=invoke_url, - headers=self.headers["call"], - json=payload, - stream=False, - ) - session = self.get_session_fn() - self.last_response = session.post(**ClientModel.desecretize(self.last_inputs)) - self._try_raise(self.last_response) - return self.last_response, session - - def _get(self, invoke_url: str, payload: dict = {}) -> Tuple[Response, Any]: - """Method for getting from the AI Playground API.""" - self.last_inputs = dict( - url=invoke_url, - headers=self.headers["call"], - json=payload, - stream=False, - ) - session = self.get_session_fn() - self.last_response = session.get(**ClientModel.desecretize(self.last_inputs)) - self._try_raise(self.last_response) - return self.last_response, session - - def _wait(self, response: Response, session: Any) -> Response: - """Wait for a response from API after an initial response is made.""" - i = 1 - while response.status_code == 202: - request_id = response.headers.get("NVCF-REQID", "") - response = session.get( - self.fetch_url_format + request_id, - headers=ClientModel.desecretize(self.headers["call"]), - ) - if response.status_code == 202: - try: - body = response.json() - except ValueError: - body = str(response) - if i > self.max_tries: - raise ValueError(f"Failed to get response with {i} tries: {body}") - self._try_raise(response) - return response - - def _try_raise(self, response: Response) -> None: - """Try to raise an error from a response""" - try: - response.raise_for_status() - except requests.HTTPError as e: - try: - rd = response.json() - except json.JSONDecodeError: - rd = response.__dict__ - rd = rd.get("_content", rd) - if isinstance(rd, bytes): - rd = rd.decode("utf-8")[5:] ## lop of data: prefix - try: - rd = json.loads(rd) - except Exception: - rd = {"detail": rd} - title = f"[{rd.get('status', '###')}] {rd.get('title', 'Unknown Error')}" - body = f"{rd.get('detail', rd.get('type', rd))}" - raise Exception(f"{title}\n{body}") from e - - #################################################################################### - ## Simple query interface to show the set of model options - - def query(self, invoke_url: str, payload: dict = {}) -> dict: - """Simple method for an end-to-end get query. Returns result dictionary""" - response, session = self._get(invoke_url, payload) - response = self._wait(response, session) - output = self._process_response(response)[0] - return output - - def _process_response(self, response: Union[str, Response]) -> List[dict]: - """General-purpose response processing for single responses and streams""" - if hasattr(response, "json"): ## For single response (i.e. non-streaming) - try: - return [response.json()] - except json.JSONDecodeError: - response = str(response.__dict__) - if isinstance(response, str): ## For set of responses (i.e. streaming) - msg_list = [] - for msg in response.split("\n\n"): - if "{" not in msg: - continue - msg_list += [json.loads(msg[msg.find("{") :])] - return msg_list - raise ValueError(f"Received ill-formed response: {response}") - - def get_available_models(self) -> dict: - """Get a dictionary of available models from the AI Playground API.""" - invoke_url = self._stagify("https://api.nvcf.nvidia.com/v2/nvcf/functions") - self.available_functions = self.query(invoke_url)["functions"] - live_fns = [v for v in self.available_functions if v.get("status") == "ACTIVE"] - return {v["name"]: v["id"] for v in live_fns} - - def _get_invoke_url( - self, model_name: Optional[str] = None, invoke_url: Optional[str] = None - ) -> str: - """Helper method to get invoke URL from a model name, URL, or endpoint stub""" - if not invoke_url: - if not model_name: - raise ValueError("URL or model name must be specified to invoke") - available_models = self.available_models or self.get_available_models() - if model_name in available_models: - invoke_url = available_models.get(model_name) - else: - for key in sorted(available_models.keys()): - if model_name in key: - invoke_url = available_models[key] - break - if not invoke_url: - raise ValueError(f"Unknown model name {model_name} specified") - if "http" not in invoke_url: - invoke_url = f"{self.call_invoke_base}/{invoke_url}" - return invoke_url - - #################################################################################### - ## Generation interface to allow users to generate new values from endpoints - - def get_req_generation( - self, - model_name: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - ) -> dict: - """Method for an end-to-end post query with NVCR post-processing.""" - invoke_url = self._get_invoke_url(model_name, invoke_url) - if payload.get("stream", False) is True: - payload = {**payload, "stream": False} - response, session = self._post(invoke_url, payload) - response = self._wait(response, session) - output, _ = self.postprocess(response) - return output - - def postprocess(self, response: Union[str, Response]) -> Tuple[dict, bool]: - """Parses a response from the AI Playground API. - Strongly assumes that the API will return a single response. - """ - msg_list = self._process_response(response) - msg, is_stopped = self._aggregate_msgs(msg_list) - msg, is_stopped = self._early_stop_msg(msg, is_stopped) - return msg, is_stopped - - def _aggregate_msgs(self, msg_list: Sequence[dict]) -> Tuple[dict, bool]: - """Dig out relevant details of aggregated message""" - content_buffer: Dict[str, Any] = dict() - content_holder: Dict[Any, Any] = dict() - is_stopped = False - for msg in msg_list: - self.last_msg = msg - if "choices" in msg: - ## Tease out ['choices'][0]...['delta'/'message'] - msg = msg.get("choices", [{}])[0] - is_stopped = msg.get("finish_reason", "") == "stop" - msg = msg.get("delta", msg.get("message", {"content": ""})) - elif "data" in msg: - ## Tease out ['data'][0]...['embedding'] - msg = msg.get("data", [{}])[0] - content_holder = msg - for k, v in msg.items(): - if k in ("content",) and k in content_buffer: - content_buffer[k] += v - else: - content_buffer[k] = v - if is_stopped: - break - content_holder = {**content_holder, **content_buffer} - return content_holder, is_stopped - - def _early_stop_msg(self, msg: dict, is_stopped: bool) -> Tuple[dict, bool]: - """Try to early-terminate streaming or generation by iterating over stop list""" - content = msg.get("content", "") - if content and self.stop: - for stop_str in self.stop: - if stop_str and stop_str in content: - msg["content"] = content[: content.find(stop_str) + 1] - is_stopped = True - return msg, is_stopped - - #################################################################################### - ## Streaming interface to allow you to iterate through progressive generations - - def get_req_stream( - self, - model: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - ) -> Iterator: - invoke_url = self._get_invoke_url(model, invoke_url) - if payload.get("stream", True) is False: - payload = {**payload, "stream": True} - self.last_inputs = dict( - url=invoke_url, - headers=self.headers["stream"], - json=payload, - stream=True, - ) - raw_inputs = ClientModel.desecretize(self.last_inputs) - response = self.get_session_fn().post(**raw_inputs) - self.last_response = response - self._try_raise(response) - call = self.copy() - - def out_gen() -> Generator[dict, Any, Any]: - ## Good for client, since it allows self.last_input - for line in response.iter_lines(): - if line and line.strip() != b"data: [DONE]": - line = line.decode("utf-8") - msg, final_line = call.postprocess(line) - yield msg - if final_line: - break - self._try_raise(response) - - return (r for r in out_gen()) - - #################################################################################### - ## Asynchronous streaming interface to allow multiple generations to happen at once. - - async def get_req_astream( - self, - model: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - ) -> AsyncIterator: - invoke_url = self._get_invoke_url(model, invoke_url) - if payload.get("stream", True) is False: - payload = {**payload, "stream": True} - self.last_inputs = dict( - url=invoke_url, - headers=self.headers["stream"], - json=payload, - ) - async with self.get_asession_fn() as session: - raw_inputs = ClientModel.desecretize(self.last_inputs) - async with session.post(**raw_inputs) as self.last_response: - self._try_raise(self.last_response) - async for line in self.last_response.content.iter_any(): - if line and line.strip() != b"data: [DONE]": - line = line.decode("utf-8") - msg, final_line = self.postprocess(line) - yield msg - if final_line: - break - - -class NVAIPlayClient(ClientModel): - """ - Higher-Level Client for interacting with AI Playground API with argument defaults. - Is subclassed by NVAIPlayLLM/NVAIPlayChat to provide a simple LangChain interface. - """ - - client: NVCRModel = Field(NVCRModel) - - model: str = Field("llama") - labels: dict = Field({}) - - temperature: float = Field(0.2, le=1.0, gt=0.0) - top_p: float = Field(0.7, le=1.0, ge=0.0) - max_tokens: int = Field(1024, le=1024, ge=32) - streaming: bool = Field(False) - - inputs: Any = Field([]) - stop: Union[Sequence[str], str] = Field([]) - - gen_keys: Sequence[str] = Field(["temperature", "top_p", "max_tokens", "streaming"]) - arg_keys: Sequence[str] = Field(["inputs", "stop"]) - valid_roles: Sequence[str] = Field(["user", "system", "assistant"]) - - class LabelModel(ClientModel): - creativity: int = Field(0, ge=0, le=9) - complexity: int = Field(0, ge=0, le=9) - verbosity: int = Field(0, ge=0, le=9) - - #################################################################################### - - def __init__(self, *args: Sequence, **kwargs: Any): - super().__init__(*args, **kwargs) - - @root_validator() - def validate_model(cls, values: Dict[str, Any]) -> Dict[str, Any]: - values["client"] = values["client"](**values) - if values.get("labels"): - values["labels"] = cls.LabelModel(**values["labels"]).dict() - return values - - @classmethod - def is_lc_serializable(cls) -> bool: - return True - - @property - def available_models(self) -> List[str]: - """List the available models that can be invoked""" - return list(getattr(self.client, "available_models", {}).keys()) - - def get_model_details(self, model: Optional[str] = None) -> dict: - """Get more meta-details about a model retrieved by a given name""" - if model is None: - model = self.model - model_key = self.client._get_invoke_url(model).split("/")[-1] - known_fns = self.client.available_functions - fn_spec = [f for f in known_fns if f.get("id") == model_key][0] - return fn_spec - - def get_generation(self, *args: Sequence, **kwargs: Any) -> dict: - """Call to client generate method with call scope""" - with self.subscope(*args, **kwargs) as call: - payload = call.get_payload(stream=False) - out = call.client.get_req_generation(call.model, payload=payload) - return out - - def get_stream(self, *args: Sequence, **kwargs: Any) -> Iterator: - """Call to client stream method with call scope""" - with self.subscope(*args, **kwargs) as call: - payload = call.get_payload(stream=True) - out = call.client.get_req_stream(call.model, payload=payload) - return out - - def get_astream(self, *args: Sequence, **kwargs: Any) -> AsyncIterator: - """Call to client astream method with call scope""" - with self.subscope(*args, **kwargs) as call: - payload = call.get_payload(stream=True) - out = call.client.get_req_astream(call.model, payload=payload) - return out - - def get_payload(self, *args: Sequence, **kwargs: Any) -> dict: - """Generates payload for the NVAIPlayClient API to send to service.""" - - def k_map(k: str) -> str: - return k if k != "streaming" else "stream" - - out = {**self.preprocess(), **{k_map(k): self.get(k) for k in self.gen_keys}} - return out - - def preprocess(self) -> dict: - """Prepares a message or list of messages for the payload""" - if ( - isinstance(self.inputs, str) - or not hasattr(self.inputs, "__iter__") - or isinstance(self.inputs, BaseMessage) - ): - self.inputs = [self.inputs] - messages = [self.prep_msg(m) for m in self.inputs] - labels = self.labels - if labels: - messages += [{"labels": labels, "role": "assistant"}] - return {"messages": messages} - - def prep_msg(self, msg: Union[str, dict, BaseMessage]) -> dict: - """Helper Method: Ensures a message is a dictionary with a role and content.""" - if isinstance(msg, str): - return dict(role="user", content=msg) - if isinstance(msg, dict): - if msg.get("role", "") not in self.valid_roles: - raise ValueError(f"Unknown message role \"{msg.get('role', '')}\"") - if msg.get("content", None) is None: - raise ValueError(f"Message {msg} has no content") - return msg - raise ValueError(f"Unknown message received: {msg} of type {type(msg)}") - - -class NVAIPlayBaseModel(NVAIPlayClient): - """ - Base class for NVIDIA AI Playground models which can interface with NVAIPlayClient. - To be subclassed by NVAIPlayLLM/NVAIPlayChat by combining with LLM/SimpleChatModel. - """ - - @property - def _llm_type(self) -> str: - """Return type of NVIDIA AI Playground Interface.""" - return "nvidia_ai_playground" - - def _call( - self, - messages: Union[List[BaseMessage], str], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManager] = None, - **kwargs: Any, - ) -> str: - """hook for LLM/SimpleChatModel. Allows for easy standard/streaming calls""" - kwargs["labels"] = kwargs.get("labels", self.labels) - kwargs["stop"] = stop if stop else getattr(self.client, "stop") - if kwargs.get("streaming", self.streaming) or kwargs["stop"]: - buffer = "" - for chunk in self._stream(messages, run_manager=run_manager, **kwargs): - buffer += chunk if isinstance(chunk, str) else chunk.text - responses = {"content": buffer} - else: - inputs = self.custom_preprocess(messages) - responses = self.get_generation(inputs, **kwargs) - outputs = self.custom_postprocess(responses) - return outputs - - def _get_filled_chunk( - self, text: str, role: Optional[str] = "assistant" - ) -> Union[GenerationChunk, ChatGenerationChunk]: - """LLM and BasicChatModel have different streaming chunk specifications""" - if isinstance(self, LLM): - return GenerationChunk(text=text) - return ChatGenerationChunk(message=ChatMessageChunk(content=text, role=role)) - - def _stream( - self, - messages: Union[List[BaseMessage], str], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManager] = None, - **kwargs: Any, - ) -> Iterator[Union[GenerationChunk, ChatGenerationChunk]]: - """Allows streaming to model!""" - inputs = self.custom_preprocess(messages) - kwargs["labels"] = kwargs.get("labels", self.labels) - kwargs["stop"] = stop if stop else getattr(self.client, "stop") - for response in self.get_stream(inputs, **kwargs): - chunk = self._get_filled_chunk(self.custom_postprocess(response)) - yield chunk - if run_manager: - async_mtypes = (AsyncCallbackManager, AsyncCallbackManagerForLLMRun) - if isinstance(run_manager, async_mtypes): - ## Edge case from LLM/SimpleChatModel default async methods - asyncio.run(run_manager.on_llm_new_token(chunk.text, chunk=chunk)) - else: - run_manager.on_llm_new_token(chunk.text, chunk=chunk) - - async def _astream( - self, - messages: Union[List[BaseMessage], str], - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManager] = None, - **kwargs: Any, - ) -> AsyncIterator[Union[GenerationChunk, ChatGenerationChunk]]: - inputs = self.custom_preprocess(messages) - kwargs["labels"] = kwargs.get("labels", self.labels) - kwargs["stop"] = stop if stop else getattr(self.client, "stop") - async for response in self.get_astream(inputs, **kwargs): - chunk = self._get_filled_chunk(self.custom_postprocess(response)) - yield chunk - if run_manager: - await run_manager.on_llm_new_token(chunk.text, chunk=chunk) - - def custom_preprocess(self, msgs: Union[str, Sequence]) -> List[Dict[str, str]]: - is_one = isinstance(msgs, (str, BaseMessage)) - is_list = not is_one and hasattr(msgs, "__iter__") - is_solo = is_list and len(msgs) == 1 and isinstance(msgs[0], (str, BaseMessage)) - msg_list: Sequence[Any] = [] - if is_one or is_solo: - msg_val: Union[str, BaseMessage] = msgs if not is_list else msgs[0] - msg_str: str = getattr(msg_val, "content", msg_val) - msg_list = re.split("///ROLE ", msg_str.strip()) - msg_list = [m for m in msg_list if m.strip()] - elif not is_list: - msg_list = [msgs] - elif is_list: - msg_list = msgs - out = [self.preprocess_msg(m) for m in msg_list] - return out - - def preprocess_msg( - self, msg: Union[str, Sequence[str], dict, BaseMessage] - ) -> Dict[str, str]: - ## Support for just simple string inputs of ///ROLE SYS etc. inputs - if isinstance(msg, str): - msg_split = re.split("SYS: |USER: |AGENT: |CONTEXT:", msg) - if len(msg_split) == 1: - return {"role": "user", "content": msg} - role_convert = { - "agent": "assistant", - "sys": "system", - "context": "context", - } - role, _, content = msg.partition(": ") - role = role_convert.get(role.strip().lower(), "user") - return {"role": role, "content": content} - ## Support for tuple inputs - if type(msg) in (list, tuple): - return {"role": msg[0], "content": msg[1]} - ## Support for manually-specified default inputs to AI Playground - if isinstance(msg, dict) and msg.get("content"): - msg["role"] = msg.get("role", "user") - return msg - ## Support for LangChain Messages - if hasattr(msg, "content"): - role_convert = {"ai": "assistant", "system": "system"} - role = getattr(msg, "type") - cont = getattr(msg, "content") - role = role_convert.get(role, "user") - if hasattr(msg, "role"): - cont = f"{getattr(msg, 'role')}: {cont}" - return {"role": role, "content": cont} - raise ValueError(f"Invalid message: {repr(msg)} of type {type(msg)}") - - def custom_postprocess(self, msg: dict) -> str: - if "content" in msg: - return msg["content"] - logger.warning( - f"Got ambiguous message in postprocessing; returning as-is: msg = {msg}" - ) - return str(msg) - - -#################################################################################### - - -class GeneralBase(NVAIPlayBaseModel): - model: str = Field("llama2_13b") - - -class CodeBase(NVAIPlayBaseModel): - model: str = Field("llama2_code_13b") - - -class InstructBase(NVAIPlayBaseModel): - model: str = Field("mistral") - - -class SteerBase(NVAIPlayBaseModel): - model: str = Field("steerlm") - arg_keys: Sequence[str] = Field(["inputs", "labels", "stop"]) - labels: dict = Field({"creativity": 0, "complexity": 9, "verbosity": 9}) - - -class ContextBase(NVAIPlayBaseModel): - model: str = Field("_qa_") - valid_roles: Sequence[str] = Field(["user", "context"]) - max_tokens: int = Field(512, ge=32, le=512) - - -class ImageBase(NVAIPlayBaseModel): - model: str = Field("neva") - arg_keys: Sequence[str] = Field(["inputs", "labels", "stop"]) - labels: dict = Field({"creativity": 0, "complexity": 9, "verbosity": 9}) - - -#################################################################################### - - -class NVAIPlayLLM(NVAIPlayBaseModel, LLM): - pass - - -class GeneralLLM(GeneralBase, LLM): - pass - - -class CodeLLM(CodeBase, LLM): - pass - - -class InstructLLM(InstructBase, LLM): - pass - - -class SteerLLM(SteerBase, LLM): - pass - - -class ContextLLM(ContextBase, LLM): - pass - - -class ImageLLM(ImageBase, LLM): - pass diff --git a/integrations/langchain/llms/nv_api_catalog/__init__.py b/integrations/langchain/llms/nv_api_catalog/__init__.py deleted file mode 100644 index f231ae513..000000000 --- a/integrations/langchain/llms/nv_api_catalog/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -**LangChain NVIDIA AI Foundation Model Playground Integration** - -This comprehensive module integrates NVIDIA's state-of-the-art AI Foundation Models, featuring advanced models for conversational AI and semantic embeddings, into the LangChain framework. It provides robust classes for seamless interaction with NVIDIA's AI models, particularly tailored for enriching conversational experiences and enhancing semantic understanding in various applications. - -**Features:** - -1. **Chat Models (`ChatNVIDIA`):** This class serves as the primary interface for interacting with NVIDIA's Foundation chat models. Users can effortlessly utilize NVIDIA's advanced models like 'Mistral' to engage in rich, context-aware conversations, applicable across diverse domains from customer support to interactive storytelling. - -2. **Semantic Embeddings (`NVIDIAEmbeddings`):** The module offers capabilities to generate sophisticated embeddings using NVIDIA's AI models. These embeddings are instrumental for tasks like semantic analysis, text similarity assessments, and contextual understanding, significantly enhancing the depth of NLP applications. - -**Installation:** - -Install this module easily using pip: - -```python -pip install langchain-nvidia-ai-endpoints -``` - -## Utilizing Chat Models: - -After setting up the environment, interact with NVIDIA AI Foundation models: -```python -from integrations.langchain.llms.nv_api_catalog import ChatNVIDIA - -ai_chat_model = ChatNVIDIA(model="llama2_13b") -response = ai_chat_model.invoke("Tell me about the LangChain integration.") -``` - -# Generating Semantic Embeddings: - -Use NVIDIA's models for creating embeddings, useful in various NLP tasks: - -```python -from integrations.langchain.llms.nv_api_catalog import NVIDIAEmbeddings - -embed_model = NVIDIAEmbeddings(model="nvolveqa_40k") -embedding_output = embed_model.embed_query("Exploring AI capabilities.") -``` -""" # noqa: E501 - -from integrations.langchain.llms.nv_api_catalog.chat_models import ChatNVIDIA -from integrations.langchain.llms.nv_api_catalog.embeddings import NVIDIAEmbeddings - -__all__ = [ - "ChatNVIDIA", - "NVIDIAEmbeddings", -] diff --git a/integrations/langchain/llms/nv_api_catalog/_common.py b/integrations/langchain/llms/nv_api_catalog/_common.py deleted file mode 100644 index 4da7efe62..000000000 --- a/integrations/langchain/llms/nv_api_catalog/_common.py +++ /dev/null @@ -1,720 +0,0 @@ -from __future__ import annotations - -import json -import logging -import os -import time -from copy import deepcopy -from functools import partial -from typing import ( - Any, - AsyncIterator, - Callable, - Dict, - Generator, - Iterator, - List, - Literal, - Optional, - Sequence, - Tuple, - Union, -) - -import aiohttp -import requests -from langchain_core.pydantic_v1 import ( - BaseModel, - Field, - PrivateAttr, - SecretStr, - root_validator, -) -from requests.models import Response - -from integrations.langchain.llms.nv_api_catalog._statics import MODEL_SPECS, Model - -logger = logging.getLogger(__name__) - -_MODE_TYPE = Literal["catalog", "nvidia", "nim", "open", "openai"] - - -class NVEModel(BaseModel): - - """ - Underlying Client for interacting with the AI Foundation Model Function API. - Leveraged by the NVIDIABaseModel to provide a simple requests-oriented interface. - Direct abstraction over NGC-recommended streaming/non-streaming Python solutions. - - NOTE: Models in the playground does not currently support raw text continuation. - """ - - ## Core defaults. These probably should not be changed - _api_key_var = "NVIDIA_API_KEY" - base_url: str = Field( - "https://api.nvcf.nvidia.com/v2/nvcf", - description="Base URL for standard inference", - ) - get_session_fn: Callable = Field(requests.Session) - get_asession_fn: Callable = Field(aiohttp.ClientSession) - endpoints: dict = Field( - { - "infer": "{base_url}/pexec/functions/{model_id}", - "status": "{base_url}/pexec/status/{request_id}", - "models": "{base_url}/functions", - } - ) - - api_key: SecretStr = Field(..., description="API Key for service of choice") - is_staging: bool = Field(False, description="Whether to use staging API") - - ## Generation arguments - timeout: float = Field(60, ge=0, description="Timeout for waiting on response (s)") - interval: float = Field(0.02, ge=0, description="Interval for pulling response") - last_inputs: dict = Field({}, description="Last inputs sent over to the server") - last_response: dict = Field({}, description="Last response sent from the server") - payload_fn: Callable = Field(lambda d: d, description="Function to process payload") - headers_tmpl: dict = Field( - ..., - description="Headers template for API calls." - " Should contain `call` and `stream` keys.", - ) - _available_functions: Optional[List[dict]] = PrivateAttr(default=None) - _available_models: Optional[dict] = PrivateAttr(default=None) - - @classmethod - def is_lc_serializable(cls) -> bool: - return True - - @property - def lc_secrets(self) -> Dict[str, str]: - return {"api_key": self._api_key_var} - - @property - def headers(self) -> dict: - """Return headers with API key injected""" - headers_ = self.headers_tmpl.copy() - for header in headers_.values(): - if "{api_key}" in header["Authorization"]: - header["Authorization"] = header["Authorization"].format( - api_key=self.api_key.get_secret_value(), - ) - return headers_ - - @root_validator(pre=True) - def validate_model(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Validate and update model arguments, including API key and formatting""" - values["api_key"] = ( - values.get(cls._api_key_var.lower()) - or values.get("api_key") - or os.getenv(cls._api_key_var) - ) - values["is_staging"] = "nvapi-stg-" in values["api_key"] - if "headers_tmpl" not in values: - call_kvs = { - "Accept": "application/json", - } - stream_kvs = { - "Accept": "text/event-stream", - "content-type": "application/json", - } - shared_kvs = { - "Authorization": "Bearer {api_key}", - "User-Agent": "langchain-nvidia-ai-endpoints", - } - values["headers_tmpl"] = { - "call": {**call_kvs, **shared_kvs}, - "stream": {**stream_kvs, **shared_kvs}, - } - return values - - @root_validator(pre=False) - def validate_model_post(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Additional validation after default values have been put in""" - values["stagify"] = partial(cls._stagify, is_staging=values["is_staging"]) - values["base_url"] = values["stagify"](values.get("base_url")) - return values - - @property - def available_models(self) -> dict: - """List the available models that can be invoked.""" - if self._available_models is not None: - return self._available_models - live_fns = self.available_functions - if "status" in live_fns[0]: - live_fns = [v for v in live_fns if v.get("status") == "ACTIVE"] - self._available_models = {v["name"]: v["id"] for v in live_fns} - else: - self._available_models = {v.get("id"): v.get("owned_by") for v in live_fns} - return self._available_models - - @property - def available_functions(self) -> list: - """List the available functions that can be invoked.""" - if self._available_functions and isinstance(self._available_functions, list): - return self._available_functions - if not self.endpoints.get("models"): - raise ValueError("No models endpoint found, so cannot retrieve model list.") - try: - invoke_url = self.endpoints.get("models", "").format(base_url=self.base_url) - query_res = self.query(invoke_url) - except Exception as e: - raise ValueError(f"Failed to query model endpoint {invoke_url}.\n{e}") - output: list = [] - if isinstance(query_res.get("functions"), list): - output = query_res.get("functions") - elif isinstance(query_res.get("data"), list): - output = query_res.get("data") - else: - raise ValueError( - f"Unexpected response when querying {invoke_url}\n{query_res}" - ) - self._available_functions = output - return self._available_functions - - def reset_method_cache(self) -> None: - """Reset method cache to force re-fetch of available functions""" - self._available_functions = None - self._available_models = None - - @staticmethod - def _stagify(path: str, is_staging: bool) -> str: - """Helper method to switch between staging and production endpoints""" - if is_staging and "stg.api" not in path: - return path.replace("api.", "stg.api.") - if not is_staging and "stg.api" in path: - return path.replace("stg.api.", "api.") - return path - - #################################################################################### - ## Core utilities for posting and getting from NV Endpoints - - def _post( - self, - invoke_url: str, - payload: Optional[dict] = {}, - ) -> Tuple[Response, Any]: - """Method for posting to the AI Foundation Model Function API.""" - self.last_inputs = { - "url": invoke_url, - "headers": self.headers["call"], - "json": self.payload_fn(payload), - "stream": False, - } - session = self.get_session_fn() - self.last_response = response = session.post(**self.last_inputs) - self._try_raise(response) - return response, session - - def _get( - self, - invoke_url: str, - payload: Optional[dict] = {}, - ) -> Tuple[Response, Any]: - """Method for getting from the AI Foundation Model Function API.""" - self.last_inputs = { - "url": invoke_url, - "headers": self.headers["call"], - "stream": False, - } - if payload: - self.last_inputs["json"] = self.payload_fn(payload) - session = self.get_session_fn() - self.last_response = response = session.get(**self.last_inputs) - self._try_raise(response) - return response, session - - def _wait(self, response: Response, session: Any) -> Response: - """Wait for a response from API after an initial response is made""" - start_time = time.time() - while response.status_code == 202: - time.sleep(self.interval) - if (time.time() - start_time) > self.timeout: - raise TimeoutError( - f"Timeout reached without a successful response." - f"\nLast response: {str(response)}" - ) - request_id = response.headers.get("NVCF-REQID", "") - endpoint_args = {"base_url": self.base_url, "request_id": request_id} - self.last_response = response = session.get( - self.endpoints["status"].format(**endpoint_args), - headers=self.headers["call"], - ) - self._try_raise(response) - return response - - def _try_raise(self, response: Response) -> None: - """Try to raise an error from a response""" - try: - response.raise_for_status() - except requests.HTTPError: - try: - rd = response.json() - if "detail" in rd and "reqId" in rd.get("detail", ""): - rd_buf = "- " + str(rd["detail"]) - rd_buf = rd_buf.replace(": ", ", Error: ").replace(", ", "\n- ") - rd["detail"] = rd_buf - except json.JSONDecodeError: - rd = response.__dict__ - rd = rd.get("_content", rd) - if isinstance(rd, bytes): - rd = rd.decode("utf-8")[5:] ## remove "data:" prefix - try: - rd = json.loads(rd) - except Exception: - rd = {"detail": rd} - status = rd.get("status", "###") - title = rd.get("title", rd.get("error", "Unknown Error")) - header = f"[{status}] {title}" - body = "" - if "requestId" in rd: - if "detail" in rd: - body += f"{rd['detail']}\n" - body += "RequestID: " + rd["requestId"] - else: - body = rd.get("detail", rd) - if str(status) == "401": - body += "\nPlease check or regenerate your API key." - raise Exception(f"{header}\n{body}") from None - - #################################################################################### - ## Simple query interface to show the set of model options - - def query( - self, - invoke_url: str, - payload: Optional[dict] = None, - request: str = "get", - ) -> dict: - """Simple method for an end-to-end get query. Returns result dictionary""" - if request == "get": - response, session = self._get(invoke_url, payload) - else: - response, session = self._post(invoke_url, payload) - response = self._wait(response, session) - output = self._process_response(response)[0] - return output - - def _process_response(self, response: Union[str, Response]) -> List[dict]: - """General-purpose response processing for single responses and streams""" - if hasattr(response, "json"): ## For single response (i.e. non-streaming) - try: - return [response.json()] - except json.JSONDecodeError: - response = str(response.__dict__) - if isinstance(response, str): ## For set of responses (i.e. streaming) - msg_list = [] - for msg in response.split("\n\n"): - if "{" not in msg: - continue - msg_list += [json.loads(msg[msg.find("{") :])] - return msg_list - raise ValueError(f"Received ill-formed response: {response}") - - def _get_invoke_url( - self, - model_name: Optional[str] = None, - invoke_url: Optional[str] = None, - endpoint: str = "", - ) -> str: - """Helper method to get invoke URL from a model name, URL, or endpoint stub""" - if not invoke_url: - endpoint_str = self.endpoints.get(endpoint, "") - if not endpoint_str: - raise ValueError(f"Unknown endpoint referenced {endpoint} provided") - if "{model_id}" in endpoint_str: - if not model_name: - raise ValueError("URL or model name must be specified to invoke") - if model_name in self.available_models: - model_id = self.available_models[model_name] - elif f"playground_{model_name}" in self.available_models: - model_id = self.available_models[f"playground_{model_name}"] - else: - available_models_str = "\n".join( - [f"{k} - {v}" for k, v in self.available_models.items()] - ) - raise ValueError( - f"Unknown model name {model_name} specified." - "\nAvailable models are:\n" - f"{available_models_str}" - ) - else: - model_id = "" - - endpoint_args = {"base_url": self.base_url, "model_id": model_id} - invoke_url = endpoint_str.format(**endpoint_args) - - if not invoke_url: - raise ValueError("URL or model name must be specified to invoke") - - return invoke_url - - #################################################################################### - ## Generation interface to allow users to generate new values from endpoints - - def get_req( - self, - model_name: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - stop: Optional[Sequence[str]] = None, - endpoint: str = "", - ) -> Response: - """Post to the API.""" - invoke_url = self._get_invoke_url(model_name, invoke_url, endpoint=endpoint) - if payload.get("stream", False) is True: - payload = {**payload, "stream": False} - response, session = self._post(invoke_url, payload) - return self._wait(response, session) - - def get_req_generation( - self, - model_name: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - stop: Optional[Sequence[str]] = None, - endpoint: str = "infer", - ) -> dict: - """Method for an end-to-end post query with NVE post-processing.""" - invoke_url = self._get_invoke_url(model_name, invoke_url, endpoint=endpoint) - response = self.get_req(model_name, payload, invoke_url) - output, _ = self.postprocess(response, stop=stop) - return output - - def postprocess( - self, response: Union[str, Response], stop: Optional[Sequence[str]] = None - ) -> Tuple[dict, bool]: - """Parses a response from the AI Foundation Model Function API. - Strongly assumes that the API will return a single response. - """ - msg_list = self._process_response(response) - msg, is_stopped = self._aggregate_msgs(msg_list) - msg, is_stopped = self._early_stop_msg(msg, is_stopped, stop=stop) - return msg, is_stopped - - def _aggregate_msgs(self, msg_list: Sequence[dict]) -> Tuple[dict, bool]: - """Dig out relevant details of aggregated message""" - content_buffer: Dict[str, Any] = dict() - content_holder: Dict[Any, Any] = dict() - usage_holder: Dict[Any, Any] = dict() #### - is_stopped = False - for msg in msg_list: - usage_holder = msg.get("usage", {}) #### - if "choices" in msg: - ## Tease out ['choices'][0]...['delta'/'message'] - msg = msg.get("choices", [{}])[0] - is_stopped = msg.get("finish_reason", "") == "stop" - msg = msg.get("delta", msg.get("message", msg.get("text", ""))) - if not isinstance(msg, dict): - msg = {"content": msg} - elif "data" in msg: - ## Tease out ['data'][0]...['embedding'] - msg = msg.get("data", [{}])[0] - content_holder = msg - for k, v in msg.items(): - if k in ("content",) and k in content_buffer: - content_buffer[k] += v - else: - content_buffer[k] = v - if is_stopped: - break - content_holder = {**content_holder, **content_buffer} - if usage_holder: - content_holder.update(token_usage=usage_holder) #### - return content_holder, is_stopped - - def _early_stop_msg( - self, msg: dict, is_stopped: bool, stop: Optional[Sequence[str]] = None - ) -> Tuple[dict, bool]: - """Try to early-terminate streaming or generation by iterating over stop list""" - content = msg.get("content", "") - if content and stop: - for stop_str in stop: - if stop_str and stop_str in content: - msg["content"] = content[: content.find(stop_str) + 1] - is_stopped = True - return msg, is_stopped - - #################################################################################### - ## Streaming interface to allow you to iterate through progressive generations - - def get_req_stream( - self, - model: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - stop: Optional[Sequence[str]] = None, - endpoint: str = "infer", - ) -> Iterator: - invoke_url = self._get_invoke_url(model, invoke_url, endpoint=endpoint) - if payload.get("stream", True) is False: - payload = {**payload, "stream": True} - self.last_inputs = { - "url": invoke_url, - "headers": self.headers["stream"], - "json": self.payload_fn(payload), - "stream": True, - } - response = self.get_session_fn().post(**self.last_inputs) - self._try_raise(response) - call = self.copy() - - def out_gen() -> Generator[dict, Any, Any]: - ## Good for client, since it allows self.last_inputs - for line in response.iter_lines(): - if line and line.strip() != b"data: [DONE]": - line = line.decode("utf-8") - msg, final_line = call.postprocess(line, stop=stop) - yield msg - if final_line: - break - self._try_raise(response) - - return (r for r in out_gen()) - - #################################################################################### - ## Asynchronous streaming interface to allow multiple generations to happen at once. - - async def get_req_astream( - self, - model: Optional[str] = None, - payload: dict = {}, - invoke_url: Optional[str] = None, - stop: Optional[Sequence[str]] = None, - endpoint: str = "infer", - ) -> AsyncIterator: - invoke_url = self._get_invoke_url(model, invoke_url, endpoint=endpoint) - if payload.get("stream", True) is False: - payload = {**payload, "stream": True} - self.last_inputs = { - "url": invoke_url, - "headers": self.headers["stream"], - "json": self.payload_fn(payload), - } - async with self.get_asession_fn() as session: - async with session.post(**self.last_inputs) as response: - self._try_raise(response) - async for line in response.content.iter_any(): - if line and line.strip() != b"data: [DONE]": - line = line.decode("utf-8") - msg, final_line = self.postprocess(line, stop=stop) - yield msg - if final_line: - break - - -class _NVIDIAClient(BaseModel): - """ - Higher-Level AI Foundation Model Function API Client with argument defaults. - Is subclassed by ChatNVIDIA to provide a simple LangChain interface. - """ - - client: NVEModel = Field(NVEModel) - - _default_model: str = "" - model: Optional[str] = Field(description="Name of the model to invoke") - infer_endpoint: str = Field("{base_url}/chat/completions") - curr_mode: _MODE_TYPE = Field("nvidia") - - #################################################################################### - - @root_validator(pre=True) - def validate_client(cls, values: Any) -> Any: - """Validate and update client arguments, including API key and formatting""" - if not values.get("client"): - values["client"] = NVEModel(**values) - elif isinstance(values["client"], NVEModel): - values["client"] = values["client"].__class__(**values["client"].dict()) - if not values.get("model"): - values["model"] = cls._default_model - assert values["model"], "No model given, with no default to fall back on." - - # the only model that doesn't support a stream parameter is kosmos_2. - # to address this, we'll use the payload_fn to remove the stream parameter for kosmos_2. - # if a user tries to set their own payload_fn, this patch will be overwritten. - # todo: get kosmos_2 api updated to support stream parameter - if values["model"] == "kosmos_2": - def kosmos_patch(payload): - payload.pop("stream", None) - return payload - values["client"].payload_fn = kosmos_patch - - return values - - @classmethod - def is_lc_serializable(cls) -> bool: - return True - - @property - def lc_secrets(self) -> Dict[str, str]: - return {"api_key": self.client._api_key_var} - - @property - def lc_attributes(self) -> Dict[str, Any]: - attributes: Dict[str, Any] = {} - if getattr(self.client, "base_url"): - attributes["base_url"] = self.client.base_url - - if self.model: - attributes["model"] = self.model - - if getattr(self.client, "endpoints"): - attributes["endpoints"] = self.client.endpoints - - return attributes - - @property - def available_functions(self) -> List[dict]: - """Map the available functions that can be invoked.""" - return self.__class__.get_available_functions(client=self) - - @property - def available_models(self) -> List[Model]: - """Map the available models that can be invoked.""" - return self.__class__.get_available_models(client=self) - - @classmethod - def get_available_functions( - cls, - mode: Optional[_MODE_TYPE] = None, - client: Optional[_NVIDIAClient] = None, - **kwargs: Any, - ) -> List[dict]: - """Map the available functions that can be invoked. Callable from class""" - nveclient = (client or cls(**kwargs)).mode(mode, **kwargs).client - nveclient.reset_method_cache() - return nveclient.available_functions - - @classmethod - def get_available_models( - cls, - mode: Optional[_MODE_TYPE] = None, - client: Optional[_NVIDIAClient] = None, - list_all: bool = False, - **kwargs: Any, - ) -> List[Model]: - """Map the available models that can be invoked. Callable from class""" - nveclient = (client or cls(**kwargs)).mode(mode, **kwargs).client - nveclient.reset_method_cache() - out = sorted( - [ - Model(id=k.replace("playground_", ""), path=v, **MODEL_SPECS.get(k, {})) - for k, v in nveclient.available_models.items() - ], - key=lambda x: f"{x.client or 'Z'}{x.id}{cls}", - ) - if not list_all: - out = [m for m in out if m.client == cls.__name__ or m.model_type is None] - return out - - def get_model_details(self, model: Optional[str] = None) -> dict: - """Get more meta-details about a model retrieved by a given name""" - if model is None: - model = self.model - model_key = self.client._get_invoke_url(model).split("/")[-1] - known_fns = self.client.available_functions - fn_spec = [f for f in known_fns if f.get("id") == model_key][0] - return fn_spec - - def get_binding_model(self) -> Optional[str]: - """Get the model to bind to the client as default payload argument""" - # if a model is configured with a model_name, always use that - # todo: move from search of available_models to a Model property - matches = [model for model in self.available_models if model.id == self.model] - if matches: - if matches[0].model_name: - return matches[0].model_name - if self.curr_mode == "catalog": - return f"playground_{self.model}" - if self.curr_mode == "nvidia": - return "" - return self.model - - def mode( - self, - mode: Optional[_MODE_TYPE] = "nvidia", - base_url: Optional[str] = None, - model: Optional[str] = None, - api_key: Optional[str] = None, - infer_path: Optional[str] = None, - models_path: Optional[str] = "{base_url}/models", - force_mode: bool = False, - force_clone: bool = True, - **kwargs: Any, - ) -> _NVIDIAClient: - """Return a client swapped to a different mode""" - if isinstance(self, str): - raise ValueError("Please construct the model before calling mode()") - out = self if not force_clone else deepcopy(self) - - if mode is None: - return out - - out.model = model or out.model - - if base_url and not force_mode: - ## If a user tries to set base_url, assume custom openapi unless forced - mode = "open" - - if mode in ["nvidia", "catalog"]: - key_var = "NVIDIA_API_KEY" - if not api_key or not api_key.startswith("nvapi-"): - api_key = os.getenv(key_var) or out.client.api_key.get_secret_value() - if not api_key.startswith("nvapi-"): - raise ValueError(f"No {key_var} in env/fed as api_key. (nvapi-...)") - - if mode in ["openai"]: - key_var = "OPENAI_API_KEY" - if not api_key or not api_key.startswith("sk-"): - api_key = os.getenv(key_var) or out.client.api_key.get_secret_value() - if not api_key.startswith("sk-"): - raise ValueError(f"No {key_var} in env/fed as api_key. (sk-...)") - - out.curr_mode = mode - if api_key: - out.client.api_key = SecretStr(api_key) - - catalog_base = "https://integrate.api.nvidia.com/v1" - openai_base = "https://api.openai.com/v1" ## OpenAI Main URL - nvcf_base = "https://api.nvcf.nvidia.com/v2/nvcf" ## NVCF Main URL - nvcf_infer = "{base_url}/pexec/functions/{model_id}" ## Inference endpoints - nvcf_status = "{base_url}/pexec/status/{request_id}" ## 202 wait handle - nvcf_models = "{base_url}/functions" ## Model listing - - if mode == "nvidia": - ## Classic support for nvcf-backed foundation model endpoints. - out.client.base_url = base_url or nvcf_base - out.client.endpoints = { - "infer": nvcf_infer, ## Per-model inference - "status": nvcf_status, ## 202 wait handle - "models": nvcf_models, ## Model listing - } - - elif mode == "catalog": - ## NVIDIA API Catalog Integration: OpenAPI-spec gateway over NVCF endpoints - out.client.base_url = base_url or catalog_base - out.client.endpoints["infer"] = infer_path or out.infer_endpoint - ## API Catalog is early, so no models list yet. Undercut to nvcf for now. - out.client.endpoints["models"] = nvcf_models.format(base_url=nvcf_base) - - elif mode == "open" or mode == "nim": - ## OpenAPI-style specs to connect to NeMo Inference Microservices etc. - ## Most generic option, requires specifying base_url - assert base_url, "Base URL must be specified for open/nim mode" - out.client.base_url = base_url - out.client.endpoints["infer"] = infer_path or out.infer_endpoint - out.client.endpoints["models"] = models_path or "{base_url}/models" - - elif mode == "openai": - ## OpenAI-style specification to connect to OpenAI endpoints - out.client.base_url = base_url or openai_base - out.client.endpoints["infer"] = infer_path or out.infer_endpoint - out.client.endpoints["models"] = models_path or "{base_url}/models" - - else: - options = ["catalog", "nvidia", "nim", "open", "openai"] - raise ValueError(f"Unknown mode: `{mode}`. Expected one of {options}.") - - out.client.reset_method_cache() - - return out diff --git a/integrations/langchain/llms/nv_api_catalog/_statics.py b/integrations/langchain/llms/nv_api_catalog/_statics.py deleted file mode 100644 index 9971ac278..000000000 --- a/integrations/langchain/llms/nv_api_catalog/_statics.py +++ /dev/null @@ -1,113 +0,0 @@ -from typing import Optional - -from langchain_core.pydantic_v1 import BaseModel - - -class Model(BaseModel): - id: str - model_type: Optional[str] = None - model_name: Optional[str] = None - client: Optional[str] = None - path: str - - -MODEL_SPECS = { - "playground_smaug_72b": {"model_type": "chat"}, - "playground_kosmos_2": {"model_type": "image_in"}, - "playground_llama2_70b": {"model_type": "chat"}, - "playground_nvolveqa_40k": {"model_type": "embedding"}, - "playground_nemotron_qa_8b": {"model_type": "qa"}, - "playground_gemma_7b": {"model_type": "chat"}, - "playground_mistral_7b": {"model_type": "chat"}, - "playground_mamba_chat": {"model_type": "chat"}, - "playground_phi2": {"model_type": "chat"}, - "playground_sdxl": {"model_type": "image_out"}, - "playground_nv_llama2_rlhf_70b": {"model_type": "chat"}, - "playground_neva_22b": {"model_type": "image_in"}, - "playground_yi_34b": {"model_type": "chat"}, - "playground_nemotron_steerlm_8b": {"model_type": "chat"}, - "playground_cuopt": {"model_type": "cuopt"}, - "playground_llama_guard": {"model_type": "classifier"}, - "playground_starcoder2_15b": {"model_type": "completion"}, - "playground_deplot": {"model_type": "image_in"}, - "playground_llama2_code_70b": {"model_type": "chat"}, - "playground_gemma_2b": {"model_type": "chat"}, - "playground_seamless": {"model_type": "translation"}, - "playground_mixtral_8x7b": {"model_type": "chat"}, - "playground_fuyu_8b": {"model_type": "image_in"}, - "playground_llama2_code_34b": {"model_type": "chat"}, - "playground_llama2_code_13b": {"model_type": "chat"}, - "playground_steerlm_llama_70b": {"model_type": "chat"}, - "playground_clip": {"model_type": "similarity"}, - "playground_llama2_13b": {"model_type": "chat"}, -} - -MODEL_SPECS.update( - { - 'ai-codellama-70b': {'model_type': 'chat', 'model_name': 'meta/codellama-70b'}, - # 'ai-embedding-2b': {'model_type': 'embedding'}, - 'ai-fuyu-8b': {'model_type': 'image_in'}, - 'ai-gemma-7b': {'model_type': 'chat', 'model_name': 'google/gemma-7b'}, - 'ai-google-deplot': {'model_type': 'image_in'}, - 'ai-llama2-70b': {'model_type': 'chat', 'model_name': 'meta/llama2-70b'}, - 'ai-microsoft-kosmos-2': {'model_type': 'image_in'}, - 'ai-mistral-7b-instruct-v2': {'model_type': 'chat', 'model_name': 'mistralai/mistral-7b-instruct-v0.2'}, - 'ai-mixtral-8x7b-instruct': {'model_type': 'chat', 'model_name': 'mistralai/mixtral-8x7b-instruct-v0.1'}, - 'ai-neva-22b': {'model_type': 'image_in'}, - # 'ai-reranking-4b': {'model_type': 'chat'}, - # 'ai-sdxl-turbo': {'model_type': 'image_out'}, - # 'ai-stable-diffusion-xl-base': {'model_type': 'iamge_out'}, - } -) - - -MODEL_SPECS.update( - { - "babbage-002": {"model_type": "completion"}, - "dall-e-2": {"model_type": "image_out"}, - "dall-e-3": {"model_type": "image_out"}, - "davinci-002": {"model_type": "completion"}, - "gpt-3.5-turbo-0125": {"model_type": "chat"}, - "gpt-3.5-turbo-0301": {"model_type": "chat"}, - "gpt-3.5-turbo-0613": {"model_type": "chat"}, - "gpt-3.5-turbo-1106": {"model_type": "chat"}, - "gpt-3.5-turbo-16k-0613": {"model_type": "chat"}, - "gpt-3.5-turbo-16k": {"model_type": "chat"}, - "gpt-3.5-turbo-instruct-0914": {"model_type": "completion"}, - "gpt-3.5-turbo-instruct": {"model_type": "completion"}, - "gpt-3.5-turbo": {"model_type": "chat"}, - "gpt-4-0125-preview": {"model_type": "chat"}, - "gpt-4-0613": {"model_type": "chat"}, - "gpt-4-1106-preview": {"model_type": "chat"}, - "gpt-4-turbo-preview": {"model_type": "chat"}, - "gpt-4-vision-preview": {"model_type": "chat"}, - "gpt-4": {"model_type": "chat"}, - "text-embedding-3-large": {"model_type": "embedding"}, - "text-embedding-3-small": {"model_type": "embedding"}, - "text-embedding-ada-002": {"model_type": "embedding"}, - "tts-1-1106": {"model_type": "tts"}, - "tts-1-hd-1106": {"model_type": "tts"}, - "tts-1-hd": {"model_type": "tts"}, - "tts-1": {"model_type": "tts"}, - "whisper-1": {"model_type": "asr"}, - } -) - -client_map = { - "asr": "None", - "chat": "ChatNVIDIA", - "classifier": "None", - "completion": "NVIDIA", - "cuopt": "None", - "embedding": "NVIDIAEmbeddings", - "image_in": "ChatNVIDIA", - "image_out": "ImageGenNVIDIA", - "qa": "ChatNVIDIA", - "similarity": "None", - "translation": "None", - "tts": "None", -} - -MODEL_SPECS = { - k: {**v, "client": client_map[v["model_type"]]} for k, v in MODEL_SPECS.items() -} diff --git a/integrations/langchain/llms/nv_api_catalog/callbacks.py b/integrations/langchain/llms/nv_api_catalog/callbacks.py deleted file mode 100644 index 7f74e015b..000000000 --- a/integrations/langchain/llms/nv_api_catalog/callbacks.py +++ /dev/null @@ -1,305 +0,0 @@ -"""Callback Handler that prints to std out.""" -from __future__ import annotations - -import logging -import threading -from collections import defaultdict -from contextlib import contextmanager -from contextvars import ContextVar -from typing import Any, Dict, Generator, List, Optional - -from langchain_core.callbacks import BaseCallbackHandler -from langchain_core.outputs import LLMResult -from langchain_core.tracers.context import register_configure_hook - -logger = logging.getLogger(__name__) - -## This module contains output parsers for OpenAI tools. Set here for version control - -""" -### **Usage/Cost Tracking** - -For tracking model usage and , you can use the `get_usage_callback` context manager to track token information similar to `get_openai_callback`. Additionally, you can specify custom price mappings as necessary (`price_map` argument), or provide a custom callback manager for advanced use-cases (`callback` argument). - -**NOTE:** This feature is currently not supported in streaming modes, but works fine for non-streaming `invoke/ainvoke` queries. - -``` -from integrations.langchain.llms.nv_api_catalog import ChatNVIDIA, NVIDIAEmbeddings -from integrations.langchain.llms.nv_api_catalog.callbacks import get_usage_callback - -## Assume a price map per 1K tokens for a particular deployment plan -price_map = { - "mixtral_8x7b": 0.00060, - "gemma_7b": 0.0002, - "nvolveqa_40k": 0.000016, -} - -llm_large = ChatNVIDIA(model="mixtral_8x7b", temperature=0.1) -llm_small = ChatNVIDIA(model="gemma_2b", temperature=0.1) -embedding = NVIDIAEmbeddings(model="nvolveqa_40k") -models = [llm_large, llm_small, embedding] - -with get_usage_callback(price_map=price_map) as cb: - ## Reset either at beginning or end. Statistics will run until cleared - cb.reset() - - llm_large.invoke("Tell me a joke") - print(cb, end="\n\n") - # llm_large.invoke("Tell me a short joke") - # print(cb, end="\n\n") - # ## Tracking through streaming coming soon - # [_ for _ in llm_small.stream("Tell me a joke")] - # print(cb, end="\n[Should not change yet]\n\n") - ## Tracking for streaming supported - embedding.embed_query("What a nice day :D") - print(cb, end="\n\n") - # ## Sanity check. Should still be tracked fine - # llm_small.invoke("Tell me a long joke") - # print(cb, end="\n\n") - -## Out of scope. Will not be tracked -llm_small.invoke("Tell me a short joke") -print(cb, end="\n[Should not change ever]\n\n") -cb.model_usage -``` -""" - - -DEFAULT_MODEL_COST_PER_1K_TOKENS: Dict[str, float] = {} - - -def standardize_model_name( - model_name: str, - price_map: dict = {}, - is_completion: bool = False, -) -> str: - """ - Standardize the model name to a format that can be used in the OpenAI API. - - Args: - model_name: Model name to standardize. - is_completion: Whether the model is used for completion or not. - Defaults to False. - - Returns: - Standardized model name. - - """ - model_name = model_name.lower() - if ".ft-" in model_name: - model_name = model_name.split(".ft-")[0] + "-azure-finetuned" - if ":ft-" in model_name: - model_name = model_name.split(":")[0] + "-finetuned-legacy" - if "ft:" in model_name: - model_name = model_name.split(":")[1] + "-finetuned" - if model_name.startswith("playground_"): - model_name = model_name.replace("playground_", "") - if ( - is_completion - and model_name + "-completion" in price_map - and ( - model_name.startswith("gpt-4") - or model_name.startswith("gpt-3.5") - or model_name.startswith("gpt-35") - or ("finetuned" in model_name and "legacy" not in model_name) - ) - ): - return model_name + "-completion" - else: - return model_name - - -def get_token_cost_for_model( - model_name: str, num_tokens: int, price_map: dict, is_completion: bool = False -) -> float: - """ - Get the cost in USD for a given model and number of tokens. - - Args: - model_name: Name of the model - num_tokens: Number of tokens. - price_map: Map of model names to cost per 1000 tokens. - Defaults to AI Foundation Endpoint pricing per https://www.together.ai/pricing. - is_completion: Whether the model is used for completion or not. - Defaults to False. - - Returns: - Cost in USD. - """ - model_name = standardize_model_name( - model_name, - price_map, - is_completion=is_completion, - ) - if model_name not in price_map: - raise ValueError( - f"Unknown model: {model_name}. Please provide a valid model name." - "Known models are: " + ", ".join(price_map.keys()) - ) - return price_map[model_name] * (num_tokens / 1000) - - -class UsageCallbackHandler(BaseCallbackHandler): - """Callback Handler that tracks OpenAI info.""" - - ## Per-model statistics - _model_usage: defaultdict = defaultdict( - lambda: { - "total_tokens": 0, - "prompt_tokens": 0, - "completion_tokens": 0, - "successful_requests": 0, - "total_cost": 0.0, - } - ) - - llm_output: dict = {} - price_map: dict = {k: v for k, v in DEFAULT_MODEL_COST_PER_1K_TOKENS.items()} - - ## Aggregate statistics, compatible with OpenAICallbackHandler - @property - def total_tokens(self) -> int: - """Total tokens used.""" - return self._model_usage["total"]["total_tokens"] - - @property - def prompt_tokens(self) -> int: - """Prompt tokens used.""" - return self._model_usage["total"]["prompt_tokens"] - - @property - def completion_tokens(self) -> int: - """Completion tokens used.""" - return self._model_usage["total"]["completion_tokens"] - - @property - def successful_requests(self) -> int: - """Total successful requests.""" - return self._model_usage["total"]["successful_requests"] - - @property - def total_cost(self) -> float: - """Total cost in USD.""" - return self._model_usage["total"]["total_cost"] - - def __init__(self) -> None: - super().__init__() - self._lock = threading.Lock() - - def __repr__(self) -> str: - return ( - f"Tokens Used: {self.total_tokens}\n" - f"\tPrompt Tokens: {self.prompt_tokens}\n" - f"\tCompletion Tokens: {self.completion_tokens}\n" - f"Successful Requests: {self.successful_requests}\n" - f"Total Cost (USD): ${self.total_cost:.8g}" - ) - - @property - def model_usage(self) -> dict: - """Whether to call verbose callbacks even if verbose is False.""" - return dict(self._model_usage) - - def reset(self) -> None: - """Reset the model usage.""" - with self._lock: - self._model_usage.clear() - - @property - def always_verbose(self) -> bool: - """Whether to call verbose callbacks even if verbose is False.""" - return True - - def on_llm_start( - self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any - ) -> None: - pass - - def on_llm_new_token(self, token: str, **kwargs: Any) -> None: - pass - - def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None: - if not response.llm_output: - response.llm_output = {} - if not self.llm_output: - self.llm_output = {} - - response.llm_output = {**self.llm_output, **response.llm_output} - self.llm_output = {} - - if not response.llm_output: - return None - - # compute tokens and cost for this request - token_usage = response.llm_output.get( - "token_usage", response.llm_output.get("usage", {}) - ) - completion_tokens = token_usage.get("completion_tokens", 0) - prompt_tokens = token_usage.get("prompt_tokens", 0) - model_name = response.llm_output.get("model_name", "") - if model_name in self.price_map: - completion_cost = get_token_cost_for_model( - model_name, completion_tokens, self.price_map, is_completion=True - ) - prompt_cost = get_token_cost_for_model( - model_name, prompt_tokens, self.price_map - ) - else: - completion_cost = 0 - prompt_cost = 0 - - # update shared state behind lock - with self._lock: - for base in (self._model_usage["total"], self._model_usage[model_name]): - base["total_tokens"] += token_usage.get("total_tokens", 0) - base["prompt_tokens"] += prompt_tokens - base["completion_tokens"] += completion_tokens - base["total_cost"] += prompt_cost + completion_cost - base["successful_requests"] += 1 - for key in base.keys(): - base[key] = round(base[key], 10) - - def __copy__(self) -> "UsageCallbackHandler": - """Return a copy of the callback handler.""" - return self - - def __deepcopy__(self, memo: Any) -> "UsageCallbackHandler": - """Return a deep copy of the callback handler.""" - return self - - -## get_usage_callack variable construction, registration, management - -usage_callback_var: ContextVar[Optional[UsageCallbackHandler]] = ContextVar( - "usage_callback", default=None -) - -register_configure_hook(usage_callback_var, True) - - -@contextmanager -def get_usage_callback( - price_map: dict = {}, - callback: Optional[UsageCallbackHandler] = None, -) -> Generator[UsageCallbackHandler, None, None]: - """Get the OpenAI callback handler in a context manager. - which conveniently exposes token and cost information. - - Returns: - OpenAICallbackHandler: The OpenAI callback handler. - - Example: - >>> with get_openai_callback() as cb: - ... # Use the OpenAI callback handler - """ - if not callback: - callback = UsageCallbackHandler() - if hasattr(callback, "price_map"): - if hasattr(callback, "_lock"): - with callback._lock: - callback.price_map.update(price_map) - else: - callback.price_map.update(price_map) - usage_callback_var.set(callback) - yield callback - usage_callback_var.set(None) diff --git a/integrations/langchain/llms/nv_api_catalog/chat_models.py b/integrations/langchain/llms/nv_api_catalog/chat_models.py deleted file mode 100644 index fa51b8a79..000000000 --- a/integrations/langchain/llms/nv_api_catalog/chat_models.py +++ /dev/null @@ -1,410 +0,0 @@ -"""Chat Model Components Derived from ChatModel/NVIDIA""" - -from __future__ import annotations - -import base64 -import io -import logging -import os -import sys -import urllib.parse -from typing import ( - Any, - AsyncIterator, - Callable, - Dict, - Iterator, - List, - Literal, - Mapping, - Optional, - Sequence, - Type, - Union, -) - -import requests -from langchain_core.callbacks.manager import ( - AsyncCallbackManagerForLLMRun, - CallbackManagerForLLMRun, -) -from langchain_core.language_models import BaseChatModel, LanguageModelInput -from langchain_core.messages import ( - BaseMessage, - ChatMessage, - ChatMessageChunk, -) -from langchain_core.outputs import ( - ChatGeneration, - ChatGenerationChunk, - ChatResult, -) -from langchain_core.pydantic_v1 import BaseModel, Field -from langchain_core.runnables import Runnable -from langchain_core.runnables.config import run_in_executor -from langchain_core.tools import BaseTool - -from integrations.langchain.llms.nv_api_catalog import _common as nvidia_ai_endpoints - -_CallbackManager = Union[AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun] -_DictOrPydanticClass = Union[Dict[str, Any], Type[BaseModel]] -_DictOrPydantic = Union[Dict, BaseModel] - -try: - import PIL.Image - - has_pillow = True -except ImportError: - has_pillow = False - -logger = logging.getLogger(__name__) - - -def _is_url(s: str) -> bool: - try: - result = urllib.parse.urlparse(s) - return all([result.scheme, result.netloc]) - except Exception as e: - logger.debug(f"Unable to parse URL: {e}") - return False - - -def _resize_image(img_data: bytes, max_dim: int = 1024) -> str: - if not has_pillow: - print( # noqa: T201 - "Pillow is required to resize images down to reasonable scale." - " Please install it using `pip install pillow`." - " For now, not resizing; may cause NVIDIA API to fail." - ) - return base64.b64encode(img_data).decode("utf-8") - image = PIL.Image.open(io.BytesIO(img_data)) - max_dim_size = max(image.size) - aspect_ratio = max_dim / max_dim_size - new_h = int(image.size[1] * aspect_ratio) - new_w = int(image.size[0] * aspect_ratio) - resized_image = image.resize((new_w, new_h), PIL.Image.Resampling.LANCZOS) - output_buffer = io.BytesIO() - resized_image.save(output_buffer, format="JPEG") - output_buffer.seek(0) - resized_b64_string = base64.b64encode(output_buffer.read()).decode("utf-8") - return resized_b64_string - - -def _url_to_b64_string(image_source: str) -> str: - b64_template = "data:image/png;base64,{b64_string}" - try: - if _is_url(image_source): - response = requests.get(image_source) - response.raise_for_status() - encoded = base64.b64encode(response.content).decode("utf-8") - if sys.getsizeof(encoded) > 200000: - ## (VK) Temporary fix. NVIDIA API has a limit of 250KB for the input. - encoded = _resize_image(response.content) - return b64_template.format(b64_string=encoded) - elif image_source.startswith("data:image"): - return image_source - elif os.path.exists(image_source): - with open(image_source, "rb") as f: - encoded = base64.b64encode(f.read()).decode("utf-8") - return b64_template.format(b64_string=encoded) - else: - raise ValueError( - "The provided string is not a valid URL, base64, or file path." - ) - except Exception as e: - raise ValueError(f"Unable to process the provided image source: {e}") - - -class ChatNVIDIA(nvidia_ai_endpoints._NVIDIAClient, BaseChatModel): - """NVIDIA chat model. - - Example: - .. code-block:: python - - from integrations.langchain.llms.nv_api_catalog import ChatNVIDIA - - - model = ChatNVIDIA(model="llama2_13b") - response = model.invoke("Hello") - """ - - _default_model: str = "mixtral_8x7b" - infer_endpoint: str = Field("{base_url}/chat/completions") - model: str = Field(_default_model, description="Name of the model to invoke") - temperature: Optional[float] = Field(description="Sampling temperature in [0, 1]") - max_tokens: Optional[int] = Field(description="Maximum # of tokens to generate") - top_p: Optional[float] = Field(description="Top-p for distribution sampling") - seed: Optional[int] = Field(description="The seed for deterministic results") - bad: Optional[Sequence[str]] = Field(description="Bad words to avoid (cased)") - stop: Optional[Sequence[str]] = Field(description="Stop words (cased)") - labels: Optional[Dict[str, float]] = Field(description="Steering parameters") - streaming: bool = Field(True) - - @property - def _llm_type(self) -> str: - """Return type of NVIDIA AI Foundation Model Interface.""" - return "chat-nvidia-ai-playground" - - def _generate( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> ChatResult: - responses = self._call(messages, stop=stop, run_manager=run_manager, **kwargs) - self._set_callback_out(responses, run_manager) - message = ChatMessage(**self.custom_postprocess(responses)) - generation = ChatGeneration(message=message) - return ChatResult(generations=[generation], llm_output=responses) - - async def _agenerate( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> ChatResult: - return await run_in_executor( - None, - self._generate, - messages, - stop=stop, - run_manager=run_manager.get_sync() if run_manager else None, - **kwargs, - ) - - def _call( - self, - messages: List[BaseMessage], - stop: Optional[Sequence[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> dict: - """Invoke on a single list of chat messages.""" - inputs = self.custom_preprocess(messages) - responses = self.get_generation(inputs=inputs, stop=stop, **kwargs) - return responses - - def _get_filled_chunk(self, **kwargs: Any) -> ChatGenerationChunk: - """Fill the generation chunk.""" - return ChatGenerationChunk(message=ChatMessageChunk(**kwargs)) - - def _stream( - self, - messages: List[BaseMessage], - stop: Optional[Sequence[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> Iterator[ChatGenerationChunk]: - """Allows streaming to model!""" - inputs = self.custom_preprocess(messages) - for response in self.get_stream(inputs=inputs, stop=stop, **kwargs): - self._set_callback_out(response, run_manager) - chunk = self._get_filled_chunk(**self.custom_postprocess(response)) - if run_manager: - run_manager.on_llm_new_token(chunk.text, chunk=chunk) - yield chunk - - async def _astream( - self, - messages: List[BaseMessage], - stop: Optional[Sequence[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> AsyncIterator[ChatGenerationChunk]: - inputs = self.custom_preprocess(messages) - async for response in self.get_astream(inputs=inputs, stop=stop, **kwargs): - self._set_callback_out(response, run_manager) - chunk = self._get_filled_chunk(**self.custom_postprocess(response)) - if run_manager: - await run_manager.on_llm_new_token(chunk.text, chunk=chunk) - yield chunk - - def _set_callback_out( - self, - result: dict, - run_manager: Optional[_CallbackManager], - ) -> None: - result.update({"model_name": self.model}) - if run_manager: - for cb in run_manager.handlers: - if hasattr(cb, "llm_output"): - cb.llm_output = result - - def custom_preprocess( - self, msg_list: Sequence[BaseMessage] - ) -> List[Dict[str, str]]: - return [self.preprocess_msg(m) for m in msg_list] - - def _process_content(self, content: Union[str, List[Union[dict, str]]]) -> str: - if isinstance(content, str): - return content - string_array: list = [] - - for part in content: - if isinstance(part, str): - string_array.append(part) - elif isinstance(part, Mapping): - # OpenAI Format - if "type" in part: - if part["type"] == "text": - string_array.append(str(part["text"])) - elif part["type"] == "image_url": - img_url = part["image_url"] - if isinstance(img_url, dict): - if "url" not in img_url: - raise ValueError( - f"Unrecognized message image format: {img_url}" - ) - img_url = img_url["url"] - b64_string = _url_to_b64_string(img_url) - string_array.append(f'') - else: - raise ValueError( - f"Unrecognized message part type: {part['type']}" - ) - else: - raise ValueError(f"Unrecognized message part format: {part}") - return "".join(string_array) - - def preprocess_msg(self, msg: BaseMessage) -> Dict[str, str]: - if isinstance(msg, BaseMessage): - role_convert = {"ai": "assistant", "human": "user"} - if isinstance(msg, ChatMessage): - role = msg.role - else: - role = msg.type - role = role_convert.get(role, role) - content = self._process_content(msg.content) - return {"role": role, "content": content} - raise ValueError(f"Invalid message: {repr(msg)} of type {type(msg)}") - - def custom_postprocess(self, msg: dict) -> dict: - kw_left = msg.copy() - out_dict = { - "role": kw_left.pop("role", "assistant") or "assistant", - "name": kw_left.pop("name", None), - "id": kw_left.pop("id", None), - "content": kw_left.pop("content", "") or "", - "additional_kwargs": {}, - "response_metadata": {}, - } - for k in list(kw_left.keys()): - if "tool" in k: - out_dict["additional_kwargs"][k] = kw_left.pop(k) - out_dict["response_metadata"] = kw_left - return out_dict - - ###################################################################################### - ## Core client-side interfaces - - def get_generation( - self, - inputs: Sequence[Dict], - **kwargs: Any, - ) -> dict: - """Call to client generate method with call scope""" - stop = kwargs["stop"] = kwargs.get("stop") or self.stop - payload = self.get_payload(inputs=inputs, stream=False, **kwargs) - out = self.client.get_req_generation(self.model, stop=stop, payload=payload) - return out - - def get_stream( - self, - inputs: Sequence[Dict], - **kwargs: Any, - ) -> Iterator: - """Call to client stream method with call scope""" - stop = kwargs["stop"] = kwargs.get("stop") or self.stop - payload = self.get_payload(inputs=inputs, stream=True, **kwargs) - return self.client.get_req_stream(self.model, stop=stop, payload=payload) - - def get_astream( - self, - inputs: Sequence[Dict], - **kwargs: Any, - ) -> AsyncIterator: - """Call to client astream methods with call scope""" - stop = kwargs["stop"] = kwargs.get("stop") or self.stop - payload = self.get_payload(inputs=inputs, stream=True, **kwargs) - return self.client.get_req_astream(self.model, stop=stop, payload=payload) - - def get_payload(self, inputs: Sequence[Dict], **kwargs: Any) -> dict: - """Generates payload for the _NVIDIAClient API to send to service.""" - attr_kwargs = { - "temperature": self.temperature, - "max_tokens": self.max_tokens, - "top_p": self.top_p, - "seed": self.seed, - "bad": self.bad, - "stop": self.stop, - "labels": self.labels, - } - if model_name := self.get_binding_model(): - attr_kwargs["model"] = model_name - attr_kwargs = {k: v for k, v in attr_kwargs.items() if v is not None} - new_kwargs = {**attr_kwargs, **kwargs} - return self.prep_payload(inputs=inputs, **new_kwargs) - - def prep_payload(self, inputs: Sequence[Dict], **kwargs: Any) -> dict: - """Prepares a message or list of messages for the payload""" - messages = [self.prep_msg(m) for m in inputs] - if kwargs.get("labels"): - # (WFH) Labels are currently (?) always passed as an assistant - # suffix message, but this API seems less stable. - messages += [{"labels": kwargs.pop("labels"), "role": "assistant"}] - if kwargs.get("stop") is None: - kwargs.pop("stop") - return {"messages": messages, **kwargs} - - def prep_msg(self, msg: Union[str, dict, BaseMessage]) -> dict: - """Helper Method: Ensures a message is a dictionary with a role and content.""" - if isinstance(msg, str): - # (WFH) this shouldn't ever be reached but leaving this here bcs - # it's a Chesterton's fence I'm unwilling to touch - return dict(role="user", content=msg) - if isinstance(msg, dict): - if msg.get("content", None) is None: - raise ValueError(f"Message {msg} has no content") - return msg - raise ValueError(f"Unknown message received: {msg} of type {type(msg)}") - - def bind_tools( - self, - tools: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool]], - *, - tool_choice: Optional[Union[dict, str, Literal["auto", "none"], bool]] = None, - **kwargs: Any, - ) -> Runnable[LanguageModelInput, BaseMessage]: - raise NotImplementedError( - "Not implemented, awaiting server-side function-recieving API" - " Consider following open-source LLM agent spec techniques:" - " https://huggingface.co/blog/open-source-llms-as-agents" - ) - - def bind_functions( - self, - functions: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable]], - function_call: Optional[str] = None, - **kwargs: Any, - ) -> Runnable[LanguageModelInput, BaseMessage]: - raise NotImplementedError( - "Not implemented, awaiting server-side function-recieving API" - " Consider following open-source LLM agent spec techniques:" - " https://huggingface.co/blog/open-source-llms-as-agents" - ) - - def with_structured_output( - self, - schema: _DictOrPydanticClass, - *, - method: Literal["function_calling", "json_mode"] = "function_calling", - return_type: Literal["parsed", "all"] = "parsed", - **kwargs: Any, - ) -> Runnable[LanguageModelInput, _DictOrPydantic]: - raise NotImplementedError( - "Not implemented, awaiting server-side function-recieving API" - " Consider following open-source LLM agent spec techniques:" - " https://huggingface.co/blog/open-source-llms-as-agents" - ) diff --git a/integrations/langchain/llms/nv_api_catalog/embeddings.py b/integrations/langchain/llms/nv_api_catalog/embeddings.py deleted file mode 100644 index 50740a008..000000000 --- a/integrations/langchain/llms/nv_api_catalog/embeddings.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Embeddings Components Derived from NVEModel/Embeddings""" -from typing import List, Literal, Optional - -from langchain_core.embeddings import Embeddings -from langchain_core.outputs.llm_result import LLMResult -from langchain_core.pydantic_v1 import Field - -from integrations.langchain.llms.nv_api_catalog._common import _NVIDIAClient -from integrations.langchain.llms.nv_api_catalog.callbacks import usage_callback_var - - -class NVIDIAEmbeddings(_NVIDIAClient, Embeddings): - """NVIDIA's AI Foundation Retriever Question-Answering Asymmetric Model.""" - - _default_model: str = "nvolveqa_40k" - infer_endpoint: str = Field("{base_url}/embeddings") - model: str = Field(_default_model, description="Name of the model to invoke") - max_length: int = Field(2048, ge=1, le=2048) - max_batch_size: int = Field(default=50) - model_type: Optional[Literal["passage", "query"]] = Field( - None, description="The type of text to be embedded." - ) - - def _embed( - self, texts: List[str], model_type: Literal["passage", "query"] - ) -> List[List[float]]: - """Embed a single text entry to either passage or query type""" - response = self.client.get_req( - model_name=self.model, - payload={ - "input": texts, - "model": self.get_binding_model() or model_type, - "encoding_format": "float", - }, - endpoint="infer", - ) - response.raise_for_status() - result = response.json() - data = result.get("data", result) - if not isinstance(data, list): - raise ValueError(f"Expected data with a list of embeddings. Got: {data}") - embedding_list = [(res["embedding"], res["index"]) for res in data] - self._invoke_callback_vars(result) - return [x[0] for x in sorted(embedding_list, key=lambda x: x[1])] - - def embed_query(self, text: str) -> List[float]: - """Input pathway for query embeddings.""" - return self._embed([text], model_type=self.model_type or "query")[0] - - def embed_documents(self, texts: List[str]) -> List[List[float]]: - """Input pathway for document embeddings.""" - # From https://catalog.ngc.nvidia.com/orgs/nvidia/teams/ai-foundation/models/nvolve-40k/documentation - # The input must not exceed the 2048 max input characters and inputs above 512 - # model tokens will be truncated. The input array must not exceed 50 input - # strings. - all_embeddings = [] - for i in range(0, len(texts), self.max_batch_size): - batch = texts[i : i + self.max_batch_size] - truncated = [ - text[: self.max_length] if len(text) > self.max_length else text - for text in batch - ] - all_embeddings.extend( - self._embed(truncated, model_type=self.model_type or "passage") - ) - return all_embeddings - - def _invoke_callback_vars(self, response: dict) -> None: - """Invoke the callback context variables if there are any.""" - callback_vars = [ - usage_callback_var.get(), - ] - llm_output = {**response, "model_name": self.model} - result = LLMResult(generations=[[]], llm_output=llm_output) - for cb_var in callback_vars: - if cb_var: - cb_var.on_llm_end(result) diff --git a/integrations/langchain/llms/nv_api_catalog/image_gen.py b/integrations/langchain/llms/nv_api_catalog/image_gen.py deleted file mode 100644 index ee30b740f..000000000 --- a/integrations/langchain/llms/nv_api_catalog/image_gen.py +++ /dev/null @@ -1,156 +0,0 @@ -"""Embeddings Components Derived from NVEModel/Embeddings""" -import base64 -from io import BytesIO -from typing import Any, List, Optional - -import requests -from langchain_core.callbacks.manager import CallbackManagerForLLMRun -from langchain_core.language_models import LLM -from langchain_core.pydantic_v1 import Field -from langchain_core.runnables import Runnable, RunnableLambda -from PIL import Image - -from integrations.langchain.llms.nv_api_catalog._common import _NVIDIAClient - - -""" -## Image Generation Models - -Due to the similarity of the underlying API, a selection of **Image Generation Models** can be supported using the LLM interface. One example is the [**Stable Diffusion XL**](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/ai-foundation/models/sdxl/api) model, which expects a prompt and some other arguments as input and produces an image (passed back as a b64-encoded string). - -``` -from integrations.langchain.llms.nv_api_catalog import ImageGenNVIDIA - -ImageGenNVIDIA.get_available_models() ## Only shows models supported by ImageGenNVIDIA - -sdxl = ImageGenNVIDIA(model="sdxl") - -out = sdxl.invoke("A picture of a cat, aesthetic") -out[:100] + "..." -``` - -To see the image, we can either convert it manually or use the built-in conversion utility `` - -``` -from integrations.langchain.llms.nv_api_catalog.image_gen import ImageParser - -# from io import BytesIO -# from PIL import Image -# import base64 - -# Image.open(BytesIO(base64.decodebytes(bytes(out[10:], "utf-8")))) -ImageParser().invoke(out) ## Runnable that does it all for you -``` - -In addition to the prompt, we can do a bit of hyperparameter tweaking and add some negative prompt components that we'd like to avoid. We will also use the `ImageParser` runnable automatically by calling the `.as_pil()` method. - -``` -sdxl = ImageGenNVIDIA( - inference_steps = 100, - negative_prompt = "ugly,bad eyes,low-res,crooked nose, smudged, painted", -) - -sdxl.as_pil().invoke("A picture of a big green dog, futuristic cyberpunk") -``` - -Note that under the hood, `as_pil` returns a merger of the `ImageGenModel` object with the `ImageParser` output parser. As a result, you may have trouble interacting with the aggregation. Note that you can reference the first half of the pipeline via `.first` or similar. - -## Example of image generation with OpenAI and DALL-E - -``` -from integrations.langchain.llms.nv_api_catalog import ImageGenNVIDIA -from getpass import getpass -import os - -if not os.environ.get("OPENAI_API_KEY", "").startswith("sk-"): - os.environ["OPENAI_API_KEY"] = getpass("Enter your OPENAI Key: ") - -llm = ImageGenNVIDIA().mode("openai") -llm.available_models -``` - -``` -from integrations.langchain.llms.nv_api_catalog import ImageGenNVIDIA - -dalle = ImageGenNVIDIA().mode("openai", model="dall-e-3") - -def payload_fn(d): - if d: - drop_keys = ["guidance_scale", "seed", "negative_prompt", "sampler"] - d = {k: v for k, v in d.items() if k not in drop_keys} - return d - -dalle.client.payload_fn = payload_fn - -dalle.as_pil().invoke("City skyline, neon green tint, aesthetic futuristic realistic") -print(dalle.client.last_inputs['json']) -dalle.client.last_response.json() -``` -""" - - -def _get_pil_from_response(data: str) -> Image.Image: - if data.startswith("url: "): - body = requests.get(data[4:], stream=True).raw - elif data.startswith("b64_json: "): - body = BytesIO(base64.decodebytes(bytes(data[10:], "utf-8"))) - else: - raise ValueError(f"Invalid response format: {str(data)[:100]}") - return Image.open(body) - - -def ImageParser() -> RunnableLambda[str, Image.Image]: - return RunnableLambda(_get_pil_from_response) - - -class ImageGenNVIDIA(_NVIDIAClient, LLM): - """NVIDIA's AI Foundation Retriever Question-Answering Asymmetric Model.""" - - _default_model: str = "sdxl" - infer_endpoint: str = Field("{base_url}/images/generations") - model: str = Field(_default_model, description="Name of the model to invoke") - negative_prompt: Optional[str] = Field(description="Sampling temperature in [0, 1]") - sampler: Optional[str] = Field(description="Sampling strategy for process") - guidance_scale: Optional[float] = Field(description="The scale of guidance") - seed: Optional[int] = Field(description="The seed for deterministic results") - - @property - def _llm_type(self) -> str: - """Return type of NVIDIA AI Foundation Model Interface.""" - return "nvidia-image-gen-model" - - def _call( - self, - prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> str: - """Run the Image Gen Model on the given prompt and input.""" - payload = { - "prompt": prompt, - "negative_prompt": kwargs.get("negative_prompt", self.negative_prompt), - "sampler": kwargs.get("sampler", self.sampler), - "guidance_scale": kwargs.get("guidance_scale", self.guidance_scale), - "seed": kwargs.get("seed", self.seed), - } - if self.get_binding_model(): - payload["model"] = self.get_binding_model() - response = self.client.get_req( - model_name=self.model, payload=payload, endpoint="infer" - ) - response.raise_for_status() - out_dict = response.json() - if "data" in out_dict: - out_dict = out_dict.get("data")[0] - if "url" in out_dict: - output = "url: {}".format(out_dict.get("url")) - elif "b64_json" in out_dict: - output = "b64_json: {}".format(out_dict.get("b64_json")) - else: - output = str(out_dict) - return output - - def as_pil(self, **kwargs: Any) -> Runnable: - """Returns a model that outputs a PIL image by default""" - return self | ImageParser(**kwargs) diff --git a/integrations/langchain/llms/nv_api_catalog/llm.py b/integrations/langchain/llms/nv_api_catalog/llm.py deleted file mode 100644 index 2624d8139..000000000 --- a/integrations/langchain/llms/nv_api_catalog/llm.py +++ /dev/null @@ -1,207 +0,0 @@ -from __future__ import annotations - -from typing import ( - Any, - AsyncIterator, - Dict, - Iterator, - List, - Optional, - Sequence, - Union, -) - -from langchain_core.callbacks.manager import ( - AsyncCallbackManagerForLLMRun, - CallbackManagerForLLMRun, -) -from langchain_core.language_models import LLM -from langchain_core.outputs import GenerationChunk -from langchain_core.pydantic_v1 import Field - -from integrations.langchain.llms.nv_api_catalog import _common as nvidia_ai_endpoints - -_CallbackManager = Union[AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun] - - -""" -### Code Generation - -These models accept the same arguments and input structure as regular chat models, but they tend to perform better on code-genreation and structured code tasks. An example of this is `llama2_code_70b`. - -``` -prompt = ChatPromptTemplate.from_messages( - [ - ( - "system", - "You are an expert coding AI. Respond only in valid python; no narration whatsoever.", - ), - ("user", "{input}"), - ] -) -chain = prompt | ChatNVIDIA(model="llama2_code_70b") | StrOutputParser() - -for txt in chain.stream({"input": "How do I solve this fizz buzz problem?"}): - print(txt, end="") -``` - -In addition, the [**StarCoder2**](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/ai-foundation/models/starcoder2-15b) model also supports code generation, but subscribes to a regular completion API. For this, you should use the LLM-style `NVIDIA` class: - -``` -from integrations.langchain.llms.nv_api_catalog import NVIDIA - -starcoder = NVIDIA(model="starcoder2_15b", stop=["```"]) - -# print(chain.invoke("Here is my implementation of fizzbuzz:\n```python\n", stop="```")) -for txt in starcoder.stream("Here is my implementation of fizzbuzz:\n```python\n"): - print(txt, end="") -``` -""" - -class NVIDIA(nvidia_ai_endpoints._NVIDIAClient, LLM): - """NVIDIA chat model. - - Example: - .. code-block:: python - - from integrations.langchain.llms.nv_api_catalog import ChatNVIDIA - - - model = NVIDIA(model="starcoder2_15b") - response = model.invoke("Here is my fizzbuzz code:\n```python\n") - """ - - _default_model: str = "starcoder2_15b" - infer_endpoint: str = Field("{base_url}/completions") - model: str = Field(_default_model, description="Name of the model to invoke") - temperature: Optional[float] = Field(description="Sampling temperature in [0, 1]") - max_tokens: Optional[int] = Field(description="Maximum # of tokens to generate") - top_p: Optional[float] = Field(description="Top-p for distribution sampling") - frequency_penalty: Optional[float] = Field(description="Frequency penalty") - presence_penalty: Optional[float] = Field(description="Presence penalty") - seed: Optional[int] = Field(description="The seed for deterministic results") - bad: Optional[Sequence[str]] = Field(description="Bad words to avoid (cased)") - stop: Optional[Sequence[str]] = Field(description="Stop words (cased)") - labels: Optional[Dict[str, float]] = Field(description="Steering parameters") - streaming: bool = Field(True) - - @property - def _llm_type(self) -> str: - """Return type of NVIDIA AI Foundation Model Interface.""" - return "nvidia-ai-playground" - - def _call( - self, - prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> str: - """Invoke on a single list of chat messages.""" - response = self.get_generation(prompt=prompt, stop=stop, **kwargs) - output = self.custom_postprocess(response) - return output - - def _stream( - self, - prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> Iterator[GenerationChunk]: - """Allows streaming to model!""" - for response in self.get_stream(prompt=prompt, stop=stop, **kwargs): - self._set_callback_out(response, run_manager) - chunk = GenerationChunk(text=self.custom_postprocess(response)) - yield chunk - if run_manager: - run_manager.on_llm_new_token(chunk.text, chunk=chunk) - - async def _astream( - self, - prompt: str, - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> AsyncIterator[GenerationChunk]: - async for response in self.get_astream(prompt=prompt, stop=stop, **kwargs): - self._set_callback_out(response, run_manager) - chunk = GenerationChunk(text=self.custom_postprocess(response)) - yield chunk - if run_manager: - await run_manager.on_llm_new_token(chunk.text, chunk=chunk) - - def _set_callback_out( - self, - result: dict, - run_manager: Optional[_CallbackManager], - ) -> None: - result.update({"model_name": self.model}) - if run_manager: - for cb in run_manager.handlers: - if hasattr(cb, "llm_output"): - cb.llm_output = result - - def custom_postprocess(self, msg: dict) -> str: - if "content" in msg: - return msg["content"] - elif "b64_json" in msg: - return msg["b64_json"] - return str(msg) - - ###################################################################################### - ## Core client-side interfaces - - def get_generation( - self, - prompt: str, - **kwargs: Any, - ) -> dict: - """Call to client generate method with call scope""" - stop = kwargs["stop"] = kwargs.get("stop") or self.stop - payload = self.get_payload(prompt=prompt, stream=False, **kwargs) - out = self.client.get_req_generation(self.model, stop=stop, payload=payload) - return out - - def get_stream( - self, - prompt: str, - **kwargs: Any, - ) -> Iterator: - """Call to client stream method with call scope""" - stop = kwargs["stop"] = kwargs.get("stop") or self.stop - payload = self.get_payload(prompt=prompt, stream=True, **kwargs) - return self.client.get_req_stream(self.model, stop=stop, payload=payload) - - def get_astream( - self, - prompt: str, - **kwargs: Any, - ) -> AsyncIterator: - """Call to client astream methods with call scope""" - stop = kwargs["stop"] = kwargs.get("stop") or self.stop - payload = self.get_payload(prompt=prompt, stream=True, **kwargs) - return self.client.get_req_astream(self.model, stop=stop, payload=payload) - - def get_payload(self, prompt: str, **kwargs: Any) -> dict: - """Generates payload for the _NVIDIAClient API to send to service.""" - attr_kwargs = { - "temperature": self.temperature, - "max_tokens": self.max_tokens, - "top_p": self.top_p, - "seed": self.seed, - "bad": self.bad, - "stop": self.stop, - "labels": self.labels, - } - if self.get_binding_model(): - attr_kwargs["model"] = self.get_binding_model() - attr_kwargs = {k: v for k, v in attr_kwargs.items() if v is not None} - new_kwargs = {**attr_kwargs, **kwargs} - return self.prep_payload(prompt=prompt, **new_kwargs) - - def prep_payload(self, prompt: str, **kwargs: Any) -> dict: - """Prepares a message or list of messages for the payload""" - if kwargs.get("stop") is None: - kwargs.pop("stop") - return {"prompt": prompt, **kwargs} diff --git a/integrations/langchain/llms/nv_api_catalog/py.typed b/integrations/langchain/llms/nv_api_catalog/py.typed deleted file mode 100644 index e69de29bb..000000000 diff --git a/integrations/langchain/llms/nv_api_catalog/tools.py b/integrations/langchain/llms/nv_api_catalog/tools.py deleted file mode 100644 index cbaaff407..000000000 --- a/integrations/langchain/llms/nv_api_catalog/tools.py +++ /dev/null @@ -1,272 +0,0 @@ -"""OpenAI chat wrapper.""" - -from __future__ import annotations - -import logging -from operator import itemgetter -from typing import ( - Any, - Callable, - Dict, - Sequence, - Type, - TypeVar, - Union, -) - -from langchain_core.language_models import LanguageModelInput -from langchain_core.messages import BaseMessage -from langchain_core.output_parsers.base import OutputParserLike -from langchain_core.output_parsers.openai_tools import ( - JsonOutputKeyToolsParser, - PydanticToolsParser, -) -from langchain_core.pydantic_v1 import BaseModel -from langchain_core.runnables import Runnable, RunnableMap, RunnablePassthrough -from langchain_core.tools import BaseTool -from langchain_core.utils.function_calling import convert_to_openai_tool - -logger = logging.getLogger(__name__) - -_BM = TypeVar("_BM", bound=BaseModel) - - -## Directly Inspired by OpenAI/MistralAI's server-side support. -## Moved here for versioning/additional integration options. - - -""" -## Agentic Behavior - -``` -%pip install --upgrade --quiet langchain numexpr langchainhub -``` - -### Example Usage Within Conversation Chains - -Like any other integration, ChatNVIDIA is fine to support chat utilities like conversation buffers by default. Below, we show the [LangChain ConversationBufferMemory](https://python.langchain.com/docs/modules/memory/types/buffer) example applied to the `mixtral_8x7b` model. - -``` -from langchain.chains import ConversationChain -from langchain.memory import ConversationBufferMemory - -chat = ChatNVIDIA(model="mixtral_8x7b", temperature=0.1, max_tokens=100, top_p=1.0) - -conversation = ConversationChain(llm=chat, memory=ConversationBufferMemory()) - -messages = [ - "Hi there!", - "I'm doing well! Just having a conversation with an AI.", - "Tell me about yourself.", -] - -for message in messages: - conversation.invoke("Hi there!")["response"] -``` - -### Simple Usage With Tooled ReACT Agent - -You can also use some of the more powerful LLM models for agentic behavior as described in [HuggingFace's Open-source LLMs as LangChain Agents](https://huggingface.co/blog/open-source-llms-as-agents) blog. - -``` -from langchain import hub -from langchain.agents import AgentExecutor, load_tools -from langchain.agents.format_scratchpad import format_log_to_str -from langchain.agents.output_parsers import ( - ReActJsonSingleInputOutputParser, -) -from langchain.tools.render import render_text_description - -# setup tools -llm = ChatNVIDIA(model="mixtral_8x7b", temperature=0.1) -tools = load_tools(["wikipedia"], llm=llm) - -# setup ReAct style prompt -prompt = hub.pull("hwchase17/react-json") -prompt = prompt.partial( - tools=render_text_description(tools), - tool_names=", ".join([t.name for t in tools]), -) - -## Add some light prompt engineering/llm guiding enforcement -prompt[1].prompt.template += "\nThought: " -chat_model_with_stop = llm.bind(stop=["\nObservation"]) - -history = [] - -def add_to_history(x, history, i=0): - history += [[i, x]] - return x - -# define the agent -agent = ( - { - "input": lambda x: x["input"], - "agent_scratchpad": lambda x: format_log_to_str(x["intermediate_steps"]), - } - | prompt - # | partial(add_to_history, history=history, i=1) - | chat_model_with_stop - # | partial(add_to_history, history=history, i=2) - | ReActJsonSingleInputOutputParser() - # | partial(add_to_history, history=history, i=3) -) - -# instantiate AgentExecutor -agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True) - -agent_executor.invoke( - { - "input": "Are there any new LLM news from NVIDIA to be aware of in 2024?'" - } -) -``` - -If an endpoint supports server-side function/tool calling (AKA the model API itself accepts a tooling message), then you can pull in the experimental `ServerToolsMixin` class as follows: - -``` -from integrations.langchain.llms.nv_api_catalog import ChatNVIDIA, ServerToolsMixin - -class TooledChatNVIDIA(ServerToolsMixin, ChatNVIDIA): - pass - -try: - tools = load_tools(["wikipedia", "llm-math"], llm=llm) - llm = TooledChatNVIDIA(model="mixtral_8x7b") - tooled_llm = llm.bind_tools(tools) - tooled_llm.invoke("Hello world!!") -except Exception as e: - print(e) - -llm.client.last_inputs["json"] -``` - -This feature is intended for experimental purposes to help users support and develop tool-calling interfaces. It's also a simple example of how to support and experiment with custom methods via Mixin incorporation. -""" - - -class ServerToolsMixin(Runnable): - def bind_tools( - self, - tools: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool]], - tool_arg: str = "tools", - conversion_fn: Callable = convert_to_openai_tool, - **kwargs: Any, - ) -> Runnable[LanguageModelInput, BaseMessage]: - """Bind tool-like objects to this chat model. - - Assumes model is compatible with OpenAI tool-calling API. - - Args: - tools: A list of tool definitions to bind to this chat model. - Can be a dictionary, pydantic model, callable, or BaseTool. Pydantic - models, callables, and BaseTools will be automatically converted to - their schema dictionary representation. - **kwargs: Any additional parameters to pass to the - :class:`~langchain.runnable.Runnable` constructor. - - EXPERIMENTAL: This method is intended for future support. Invoked in a class: - ``` - class TooledChatNVIDIA(ChatNVIDIA, ToolsMixin): - pass - - llm = TooledChatNVIDIA(model="mixtral_8x7b") - tooled_llm = llm.bind_tools(tools) - tooled_llm.invoke("Hello world!!") - ``` - - ``` - from integrations.langchain.llms.nv_api_catalog import ChatNVIDIA, ServerToolsMixin - from langchain_core.pydantic_v1 import BaseModel, Field - - # Note that the docstrings here are crucial, as they will be passed along - # to the model along with the class name. - class Multiply(BaseModel): - "Multiply two integers together." - a: int = Field(..., description="First integer") - b: int = Field(..., description="Second integer") - - class TooledChatNVIDIA(ServerToolsMixin, ChatNVIDIA): - pass - - llm = TooledChatNVIDIA().mode("openai", model="gpt-3.5-turbo-0125") - llm.bind_tools([Multiply]).invoke("Multiply for me please?") - llm.client.last_response.json() - ``` - - See langchain-mistralal/openai's implementation for more documentation. - """ - formatted_tools = [conversion_fn(tool) for tool in tools] - tool_kw = {tool_arg: formatted_tools} - return super().bind(**tool_kw, **kwargs) - - def with_structured_output( - self, - schema: Union[Dict, Type[BaseModel]], - *, - include_raw: bool = False, - tool_arg: str = "tools", - conversion_fn: Callable = convert_to_openai_tool, - **kwargs: Any, - ) -> Runnable[LanguageModelInput, Union[Dict, BaseModel]]: - """Model wrapper that returns outputs formatted to match the given schema. - - Args: - schema: The output schema as a dict or a Pydantic class. If a Pydantic class - then the model output will be an object of that class. If a dict then - the model output will be a dict. With a Pydantic class the returned - attributes will be validated, whereas with a dict they will not be. If - `method` is "function_calling" and `schema` is a dict, then the dict - must match the OpenAI function-calling spec. - include_raw: If False then only the parsed structured output is returned. If - an error occurs during model output parsing it will be raised. If True - then both the raw model response (a BaseMessage) and the parsed model - response will be returned. If an error occurs during output parsing it - will be caught and returned as well. The final output is always a dict - with keys "raw", "parsed", and "parsing_error". - - Returns: - A Runnable that takes any ChatModel input and returns as output: - - If include_raw is True then a dict with keys: - raw: BaseMessage - parsed: Pydantic BaseModel or Dictionary - parsing_error: Optional[BaseException] - - If include_raw is False then just BaseModel/Dictionary is returned - (depending on schema type). - - EXPERIMENTAL: This method is intended for future support. Invoked in a class: - ``` - class TooledChatNVIDIA(ChatNVIDIA, ToolsMixin): - pass - ``` - - See langchain-mistralal/openai's implementation for more documentation. - """ - if kwargs: - raise ValueError(f"Received unsupported arguments {kwargs}") - is_pydantic_schema = isinstance(schema, type) and issubclass(schema, BaseModel) - llm = self.bind_tools([schema], tool_arg=tool_arg, conversion_fn=conversion_fn) - if is_pydantic_schema and isinstance(schema, BaseModel): - schema_cls: Type[BaseModel] = schema - output_parser: OutputParserLike = PydanticToolsParser( - tools=[schema_cls], first_tool_only=True - ) - else: - key_name = conversion_fn(schema)["function"]["name"] - output_parser = JsonOutputKeyToolsParser( - key_name=key_name, first_tool_only=True - ) - - if include_raw: - parser_assign = RunnablePassthrough.assign( - parsed=itemgetter("raw") | output_parser, parsing_error=lambda _: None - ) - parser_none = RunnablePassthrough.assign(parsed=lambda _: None) - parser_with_fallback = parser_assign.with_fallbacks( - [parser_none], exception_key="parsing_error" - ) - return RunnableMap(raw=llm) | parser_with_fallback - else: - return llm | output_parser diff --git a/integrations/langchain/llms/triton_trt_llm.py b/integrations/langchain/llms/triton_trt_llm.py deleted file mode 100644 index 204b44e25..000000000 --- a/integrations/langchain/llms/triton_trt_llm.py +++ /dev/null @@ -1,567 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A Langchain LLM component for connecting to Triton + TensorRT LLM backend.""" -# pylint: disable=too-many-lines -import abc -import json -import logging -import queue -import random -import time -from functools import partial -from typing import Any, Callable, Dict, List, Optional, Type, Union - -import google.protobuf.json_format -import numpy as np -import tritonclient.grpc as grpcclient -import tritonclient.http as httpclient -from tritonclient.grpc.service_pb2 import ModelInferResponse -from tritonclient.utils import np_to_triton_dtype - -try: - from langchain.callbacks.manager import CallbackManagerForLLMRun - from langchain.llms.base import LLM - from langchain.pydantic_v1 import Field, root_validator - - USE_LANGCHAIN = True -except ImportError: - USE_LANGCHAIN = False - -logger = logging.getLogger(__name__) - -STOP_WORDS = ["
"] -RANDOM_SEED = 0 - -if USE_LANGCHAIN: - # pylint: disable-next=too-few-public-methods # Interface is defined by LangChain - class TensorRTLLM(LLM): # LLM class not typed in langchain - """A custom Langchain LLM class that integrates with TRTLLM triton models. - - Arguments: - server_url: (str) The URL of the Triton inference server to use. - model_name: (str) The name of the Triton TRT model to use. - temperature: (str) Temperature to use for sampling - top_p: (float) The top-p value to use for sampling - top_k: (float) The top k values use for sampling - beam_width: (int) Last n number of tokens to penalize - repetition_penalty: (int) Last n number of tokens to penalize - length_penalty: (float) The penalty to apply repeated tokens - tokens: (int) The maximum number of tokens to generate. - client: The client object used to communicate with the inference server - """ - - server_url: str = Field(None, alias="server_url") - - # # all the optional arguments - model_name: str = "ensemble" - temperature: Optional[float] = 1.0 - top_p: Optional[float] = 0 - top_k: Optional[int] = 1 - tokens: Optional[int] = 100 - beam_width: Optional[int] = 1 - repetition_penalty: Optional[float] = 1.0 - length_penalty: Optional[float] = 1.0 - client: Any - streaming: Optional[bool] = True - - @root_validator() # typing not declared in langchain - @classmethod - def validate_environment(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Validate that python package exists in environment.""" - try: - if values.get("streaming", True): - values["client"] = GrpcTritonClient(values["server_url"]) - else: - values["client"] = HttpTritonClient(values["server_url"]) - - except ImportError as err: - raise ImportError( - "Could not import triton client python package. " - "Please install it with `pip install tritonclient[all]`." - ) from err - return values - - @property - def _get_model_default_parameters(self) -> Dict[str, Any]: - return { - "tokens": self.tokens, - "top_k": self.top_k, - "top_p": self.top_p, - "temperature": self.temperature, - "repetition_penalty": self.repetition_penalty, - "length_penalty": self.length_penalty, - "beam_width": self.beam_width, - } - - @property - def _invocation_params(self, **kwargs: Any) -> Dict[str, Any]: - params = {**self._get_model_default_parameters, **kwargs} - return params - - @property - def _identifying_params(self) -> Dict[str, Any]: - """Get all the identifying parameters.""" - return { - "server_url": self.server_url, - "model_name": self.model_name, - } - - @property - def _llm_type(self) -> str: - return "triton_tensorrt" - - def _call( - self, - prompt: str, - stop: Optional[List[str]] = None, # pylint: disable=unused-argument - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> str: - """ - Execute an inference request. - - Args: - prompt: The prompt to pass into the model. - stop: A list of strings to stop generation when encountered - - Returns: - The string generated by the model - """ - - try: - - text_callback = None - if run_manager: - text_callback = partial( - run_manager.on_llm_new_token, verbose=self.verbose - ) - - invocation_params = self._get_model_default_parameters - invocation_params.update(kwargs) - invocation_params["prompt"] = [[prompt]] - model_params = self._identifying_params - model_params.update(kwargs) - request_id = str(random.randint(1, 9999999)) # nosec - - self.client.load_model(model_params["model_name"]) - if isinstance(self.client, GrpcTritonClient): - return self._streaming_request( - model_params, request_id, invocation_params, text_callback - ) - return self._request(model_params, invocation_params, text_callback) - - except Exception as e: - logger.error(f"Got error while trying reach LLM inference server. Error details: {e}") - if text_callback and isinstance(self.client, GrpcTritonClient): - text_callback("LLM inference server does not seem to up. Check chain-server container logs for more details.") - return "" - - def _streaming_request( - self, - model_params: Dict[str, Any], - request_id: str, - invocation_params: Dict[str, Any], - text_callback: Optional[Callable[[str], None]], - ) -> str: - """Request a streaming inference session.""" - - logger.debug("Generating streaming response from llm") - result_queue = self.client.request_streaming( - model_params["model_name"], request_id, **invocation_params - ) - - response = "" - start_time = time.time() - tokens_generated = 0 - for token in result_queue: - if text_callback: - text_callback(token) - tokens_generated += 1 - response = response + token - total_time = time.time() - start_time - logger.info( - "\n--- Generated %s tokens in %s seconds ---", - tokens_generated, - total_time, - ) - logger.info("--- %s tokens/sec", tokens_generated / total_time) - return response - - def _request( - self, - model_params: Dict[str, Any], - invocation_params: Dict[str, Any], - text_callback: Optional[Callable[[str], None]], - ) -> str: - """Request a streaming inference session.""" - token: str = self.client.request( - model_params["model_name"], **invocation_params - ) - if text_callback: - text_callback(token) - return token - - -class StreamingResponseGenerator(queue.Queue[Optional[str]]): - """A Generator that provides the inference results from an LLM.""" - - def __init__( - self, client: "GrpcTritonClient", request_id: str, force_batch: bool - ) -> None: - """Instantiate the generator class.""" - super().__init__() - self._client = client - self.request_id = request_id - self._batch = force_batch - - def __iter__(self) -> "StreamingResponseGenerator": - """Return self as a generator.""" - return self - - def __next__(self) -> str: - """Return the next retrieved token.""" - val = self.get() - if val is None or val in STOP_WORDS: - self._stop_stream() - raise StopIteration() - return val - - def _stop_stream(self) -> None: - """Drain and shutdown the Triton stream.""" - self._client.stop_stream( - "tensorrt_llm", self.request_id, signal=not self._batch - ) - - -class _BaseTritonClient(abc.ABC): - """An abstraction of the connection to a triton inference server.""" - - def __init__(self, server_url: str) -> None: - """Initialize the client.""" - self._server_url = server_url - self._client = self._inference_server_client(server_url) - - @property - @abc.abstractmethod - def _inference_server_client( - self, - ) -> Union[ - Type[grpcclient.InferenceServerClient], Type[httpclient.InferenceServerClient] - ]: - """Return the prefered InferenceServerClient class.""" - - @property - @abc.abstractmethod - def _infer_input( - self, - ) -> Union[Type[grpcclient.InferInput], Type[httpclient.InferInput]]: - """Return the preferred InferInput.""" - - @property - @abc.abstractmethod - def _infer_output( - self, - ) -> Union[ - Type[grpcclient.InferRequestedOutput], Type[httpclient.InferRequestedOutput] - ]: - """Return the preferred InferRequestedOutput.""" - - def load_model(self, model_name: str, timeout: int = 1000) -> None: - """Load a model into the server.""" - if self._client.is_model_ready(model_name): - return - - self._client.load_model(model_name) - t0 = time.perf_counter() - t1 = t0 - while not self._client.is_model_ready(model_name) and t1 - t0 < timeout: - t1 = time.perf_counter() - - if not self._client.is_model_ready(model_name): - raise RuntimeError(f"Failed to load {model_name} on Triton in {timeout}s") - - def get_model_list(self) -> List[str]: - """Get a list of models loaded in the triton server.""" - res = self._client.get_model_repository_index(as_json=True) - return [model["name"] for model in res["models"]] - - def get_model_concurrency(self, model_name: str, timeout: int = 1000) -> int: - """Get the modle concurrency.""" - self.load_model(model_name, timeout) - instances = self._client.get_model_config(model_name, as_json=True)["config"][ - "instance_group" - ] - return sum(instance["count"] * len(instance["gpus"]) for instance in instances) - - def _generate_stop_signals( - self, - ) -> List[Union[grpcclient.InferInput, httpclient.InferInput]]: - """Generate the signal to stop the stream.""" - inputs = [ - self._infer_input("input_ids", [1, 1], "INT32"), - self._infer_input("input_lengths", [1, 1], "INT32"), - self._infer_input("request_output_len", [1, 1], "UINT32"), - self._infer_input("stop", [1, 1], "BOOL"), - ] - inputs[0].set_data_from_numpy(np.empty([1, 1], dtype=np.int32)) - inputs[1].set_data_from_numpy(np.zeros([1, 1], dtype=np.int32)) - inputs[2].set_data_from_numpy(np.array([[0]], dtype=np.uint32)) - inputs[3].set_data_from_numpy(np.array([[True]], dtype="bool")) - return inputs - - def _generate_outputs( - self, - ) -> List[Union[grpcclient.InferRequestedOutput, httpclient.InferRequestedOutput]]: - """Generate the expected output structure.""" - return [self._infer_output("text_output")] - - def _prepare_tensor( - self, name: str, input_data: Any - ) -> Union[grpcclient.InferInput, httpclient.InferInput]: - """Prepare an input data structure.""" - t = self._infer_input( - name, input_data.shape, np_to_triton_dtype(input_data.dtype) - ) - t.set_data_from_numpy(input_data) - return t - - def _generate_inputs( # pylint: disable=too-many-arguments,too-many-locals - self, - prompt: str, - tokens: int = 300, - temperature: float = 1.0, - top_k: float = 1, - top_p: float = 0, - beam_width: int = 1, - repetition_penalty: float = 1, - length_penalty: float = 1.0, - stream: bool = True, - ) -> List[Union[grpcclient.InferInput, httpclient.InferInput]]: - """Create the input for the triton inference server.""" - query = np.array(prompt).astype(object) - request_output_len = np.array([tokens]).astype(np.uint32).reshape((1, -1)) - runtime_top_k = np.array([top_k]).astype(np.uint32).reshape((1, -1)) - runtime_top_p = np.array([top_p]).astype(np.float32).reshape((1, -1)) - temperature_array = np.array([temperature]).astype(np.float32).reshape((1, -1)) - len_penalty = np.array([length_penalty]).astype(np.float32).reshape((1, -1)) - repetition_penalty_array = ( - np.array([repetition_penalty]).astype(np.float32).reshape((1, -1)) - ) - random_seed = np.array([RANDOM_SEED]).astype(np.uint64).reshape((1, -1)) - beam_width_array = np.array([beam_width]).astype(np.uint32).reshape((1, -1)) - streaming_data = np.array([[stream]], dtype=bool) - - inputs = [ - self._prepare_tensor("text_input", query), - self._prepare_tensor("max_tokens", request_output_len), - self._prepare_tensor("top_k", runtime_top_k), - self._prepare_tensor("top_p", runtime_top_p), - self._prepare_tensor("temperature", temperature_array), - self._prepare_tensor("length_penalty", len_penalty), - self._prepare_tensor("repetition_penalty", repetition_penalty_array), - self._prepare_tensor("random_seed", random_seed), - self._prepare_tensor("beam_width", beam_width_array), - self._prepare_tensor("stream", streaming_data), - ] - return inputs - - def _trim_batch_response(self, result_str: str) -> str: - """Trim the resulting response from a batch request by removing provided prompt and extra generated text.""" - # extract the generated part of the prompt - split = result_str.split("[/INST]", 1) - generated = split[-1] - end_token = generated.find("") - if end_token == -1: - return generated - generated = generated[:end_token].strip() - return generated - - -class GrpcTritonClient(_BaseTritonClient): - """GRPC connection to a triton inference server.""" - - @property - def _inference_server_client( - self, - ) -> Type[grpcclient.InferenceServerClient]: - """Return the prefered InferenceServerClient class.""" - return grpcclient.InferenceServerClient # type: ignore - - @property - def _infer_input(self) -> Type[grpcclient.InferInput]: - """Return the preferred InferInput.""" - return grpcclient.InferInput # type: ignore - - @property - def _infer_output( - self, - ) -> Type[grpcclient.InferRequestedOutput]: - """Return the preferred InferRequestedOutput.""" - return grpcclient.InferRequestedOutput # type: ignore - - def _send_stop_signals(self, model_name: str, request_id: str) -> None: - """Send the stop signal to the Triton Inference server.""" - stop_inputs = self._generate_stop_signals() - self._client.async_stream_infer( - model_name, - stop_inputs, - request_id=request_id, - parameters={"Streaming": True}, - ) - - @staticmethod - def _process_result(result: Dict[str, str]) -> str: - """Post-process the result from the server.""" - message = ModelInferResponse() - generated_text: str = "" - google.protobuf.json_format.Parse(json.dumps(result), message) - infer_result = grpcclient.InferResult(message) - np_res = infer_result.as_numpy("text_output") - - generated_text = "" - if np_res is not None: - generated_text = "".join([token.decode() for token in np_res]) - - return generated_text - - def _stream_callback( - self, - result_queue: queue.Queue[Union[Optional[Dict[str, str]], str]], - force_batch: bool, - result: Any, - error: str, - ) -> None: - """Add streamed result to queue.""" - if error: - result_queue.put(error) - else: - response_raw = result.get_response(as_json=True) - if "outputs" in response_raw: - # the very last response might have no output, just the final flag - response = self._process_result(response_raw) - if force_batch: - response = self._trim_batch_response(response) - - if response in STOP_WORDS: - result_queue.put(None) - else: - result_queue.put(response) - - if response_raw["parameters"]["triton_final_response"]["bool_param"]: - # end of the generation - result_queue.put(None) - - # pylint: disable-next=too-many-arguments - def _send_prompt_streaming( - self, - model_name: str, - request_inputs: Any, - request_outputs: Optional[Any], - request_id: str, - result_queue: StreamingResponseGenerator, - force_batch: bool = False, - ) -> None: - """Send the prompt and start streaming the result.""" - self._client.start_stream( - callback=partial(self._stream_callback, result_queue, force_batch) - ) - self._client.async_stream_infer( - model_name=model_name, - inputs=request_inputs, - outputs=request_outputs, - request_id=request_id, - ) - - def request_streaming( - self, - model_name: str, - request_id: Optional[str] = None, - force_batch: bool = False, - **params: Any, - ) -> StreamingResponseGenerator: - """Request a streaming connection.""" - if not self._client.is_model_ready(model_name): - raise RuntimeError("Cannot request streaming, model is not loaded") - - if not request_id: - request_id = str(random.randint(1, 9999999)) # nosec - - result_queue = StreamingResponseGenerator(self, request_id, force_batch) - inputs = self._generate_inputs(stream=not force_batch, **params) - outputs = self._generate_outputs() - self._send_prompt_streaming( - model_name, - inputs, - outputs, - request_id, - result_queue, - force_batch, - ) - return result_queue - - def stop_stream( - self, model_name: str, request_id: str, signal: bool = True - ) -> None: - """Close the streaming connection.""" - if signal: - self._send_stop_signals(model_name, request_id) - self._client.stop_stream() - - -class HttpTritonClient(_BaseTritonClient): - """HTTP connection to a triton inference server.""" - - @property - def _inference_server_client( - self, - ) -> Type[httpclient.InferenceServerClient]: - """Return the prefered InferenceServerClient class.""" - return httpclient.InferenceServerClient # type: ignore - - @property - def _infer_input(self) -> Type[httpclient.InferInput]: - """Return the preferred InferInput.""" - return httpclient.InferInput # type: ignore - - @property - def _infer_output( - self, - ) -> Type[httpclient.InferRequestedOutput]: - """Return the preferred InferRequestedOutput.""" - return httpclient.InferRequestedOutput # type: ignore - - def request( - self, - model_name: str, - **params: Any, - ) -> str: - """Request inferencing from the triton server.""" - if not self._client.is_model_ready(model_name): - raise RuntimeError("Cannot request streaming, model is not loaded") - - # create model inputs and outputs - inputs = self._generate_inputs(stream=False, **params) - outputs = self._generate_outputs() - - # call the model for inference - result = self._client.infer(model_name, inputs=inputs, outputs=outputs) - result_str = "".join( - [val.decode("utf-8") for val in result.as_numpy("text_output").tolist()] - ) - - # extract the generated part of the prompt - # return(result_str) - return self._trim_batch_response(result_str) diff --git a/integrations/pandasai/llms/nv_aiplay.py b/integrations/pandasai/llms/nv_aiplay.py index eada5545c..e169ec56f 100644 --- a/integrations/pandasai/llms/nv_aiplay.py +++ b/integrations/pandasai/llms/nv_aiplay.py @@ -35,7 +35,7 @@ class NVIDIA(LLM): temperature: Optional[float] = 0.1 max_tokens: Optional[int] = 1000 top_p: Optional[float] = 1 - model: Optional[str] = "llama2_13b" + model: Optional[str] = "meta/llama3-8b-instruct" _chat_model: "ChatNVIDIA" = None @@ -44,7 +44,7 @@ def __init__(self, **kwargs): settings = get_config() if settings.llm.server_url: logger.info(f"Using llm model {settings.llm.model_name} hosted at {settings.llm.server_url} in PandasAI") - self._chat_model = ChatNVIDIA(**self._default_params).mode("nim", base_url=f"http://{settings.llm.server_url}/v1") + self._chat_model = ChatNVIDIA(**self._default_params, base_url=f"http://{settings.llm.server_url}/v1") else: logger.info(f"Using llm model {settings.llm.model_name} from api catalog in PandasAI") self._chat_model = ChatNVIDIA(**self._default_params) diff --git a/notebooks/00-llm-non-streaming-nemotron.ipynb b/notebooks/00-llm-non-streaming-nemotron.ipynb deleted file mode 100644 index f49545ef2..000000000 --- a/notebooks/00-llm-non-streaming-nemotron.ipynb +++ /dev/null @@ -1,144 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "2544460d", - "metadata": {}, - "source": [ - "# Basics: Prompt, Client, and Responses" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "1c60fd08", - "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'triton_trt_llm'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mtriton_trt_llm\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m HttpTritonClient\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'triton_trt_llm'" - ] - } - ], - "source": [ - "from triton_trt_llm import HttpTritonClient" - ] - }, - { - "cell_type": "markdown", - "id": "4c99ac30", - "metadata": {}, - "source": [ - "#### Step 1: Structure the Query in a Prompt Template" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "66c35817", - "metadata": {}, - "outputs": [], - "source": [ - "NEMOTRON_PROMPT_TEMPLATE = (\n", - " \"\"\"System\n", - "{system}\n", - "User\n", - "{prompt}\n", - "Assistant\n", - "\"\"\"\n", - ")\n", - "system = \"You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Please ensure that your responses are positive in nature.\"\n", - "prompt = 'What is the fastest land animal?'\n", - "prompt = NEMOTRON_PROMPT_TEMPLATE.format(prompt=prompt, system=system)" - ] - }, - { - "cell_type": "markdown", - "id": "fdd7ab41", - "metadata": {}, - "source": [ - "#### Step 2: Create the Triton Client" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cc94f643", - "metadata": {}, - "outputs": [], - "source": [ - "triton_url = \"llm:8000\"\n", - "client = HttpTritonClient(triton_url)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "47c24666", - "metadata": {}, - "outputs": [], - "source": [ - "pload = {\n", - " 'prompt':[[prompt]],\n", - " 'tokens':64,\n", - " 'temperature':1.0,\n", - " 'top_k':1,\n", - " 'top_p':0,\n", - " 'beam_width':1,\n", - " 'repetition_penalty':1.0,\n", - " 'length_penalty':1.0\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "443f4fbd", - "metadata": {}, - "source": [ - "#### Step 3: Load the Model and Generate Response" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "122d2f10", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "model_name = \"ensemble\"\n", - "client.load_model(model_name)\n", - "val = client.request(model_name, **pload)\n", - "print(val)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/01-llm-streaming-client.ipynb b/notebooks/01-llm-streaming-client.ipynb deleted file mode 100644 index daef4452f..000000000 --- a/notebooks/01-llm-streaming-client.ipynb +++ /dev/null @@ -1,173 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "b4268da6-98d2-4e23-a984-ce49c70d6a42", - "metadata": {}, - "source": [ - "# LLM Streaming Client\n", - "\n", - "This notebook demonstrates how to stream responses from the LLM. \n", - "\n", - "### Triton Inference Server\n", - "The LLM has been deployed to [NVIDIA Triton Inference Server](https://developer.nvidia.com/triton-inference-server) and leverages NVIDIA TensorRT-LLM (TRT-LLM), so it's optimized for low latency and high throughput inference.\n", - "\n", - "The Triton client is used to communicate with the inference server hosting the LLM and is available in [LangChain](https://github.com/langchain-ai/langchain-nvidia/tree/main/libs/trt). \n", - "\n", - "### Streaming LLM Responses\n", - "TRT-LLM on its own can provide drastic improvements to LLM response latency, but streaming can take the user-experience to the next level. Instead of waiting for an entire response to be returned from the LLM, chunks of it can be processed as soon as they are available. This helps reduce the perceived latency by the user. " - ] - }, - { - "cell_type": "markdown", - "id": "667181db-04d8-4c9d-b433-26c2a14d54e7", - "metadata": {}, - "source": [ - "### Step 1: Structure the Query in a Prompt Template" - ] - }, - { - "cell_type": "markdown", - "id": "7e206005-d153-49ce-8b54-41e425a7de17", - "metadata": {}, - "source": [ - "A [**prompt template**](https://gpt-index.readthedocs.io/en/stable/api_reference/prompts.html) is a common paradigm in LLM development. \n", - "\n", - "They are a pre-defined set of instructions provided to the LLM and guide the output produced by the model. They can contain few shot examples and guidance and are a quick way to engineer the responses from the LLM. Llama 2 accepts the [prompt format](https://huggingface.co/blog/llama2#how-to-prompt-llama-2) shown in `LLAMA_PROMPT_TEMPLATE`, which we modify to be constructed with:\n", - "- The system prompt\n", - "- The context\n", - "- The user's question" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "42a2f2cb", - "metadata": {}, - "outputs": [], - "source": [ - "LLAMA_PROMPT_TEMPLATE = (\n", - " \"[INST] <>\"\n", - " \"{system_prompt}\"\n", - " \"<>\"\n", - " \"[/INST] {context} [INST] {question} [/INST]\"\n", - ")\n", - "system_prompt = \"You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Please ensure that your responses are positive in nature.\"\n", - "context=\"\"\n", - "question='What is the fastest land animal?'\n", - "prompt = LLAMA_PROMPT_TEMPLATE.format(system_prompt=system_prompt, context=context, question=question)" - ] - }, - { - "cell_type": "markdown", - "id": "9e975c7b-3c5e-4ba6-954a-0064e6a91245", - "metadata": {}, - "source": [ - "### Step 2: Create the Triton Client" - ] - }, - { - "cell_type": "markdown", - "id": "c2858c80-ba39-43be-9978-0f8be6e6c3dd", - "metadata": {}, - "source": [ - "
\n", - "WARNING! Be sure to replace `triton_url` with the address and port that Triton is running on. \n", - "
\n", - "\n", - "Use the address and port that the Triton is available on; for example `localhost:8001`. \n", - "\n", - "**If you are running this notebook as part of the AI workflow, you dont have to replace the url**." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "5670011e-f52b-4c16-be4d-8a782b622541", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_nvidia_trt.llms import TritonTensorRTLLM\n", - "\n", - "triton_url = \"llm:8001\"\n", - "pload = {\n", - " 'tokens':300,\n", - " 'server_url': triton_url,\n", - " 'model_name': \"ensemble\",\n", - " 'temperature':1.0,\n", - " 'top_k':1,\n", - " 'top_p':0,\n", - " 'beam_width':1,\n", - " 'repetition_penalty':1.0,\n", - " 'length_penalty':1.0\n", - "}\n", - "client = TritonTensorRTLLM(**pload)" - ] - }, - { - "cell_type": "markdown", - "id": "03676629-33d8-46d8-b5fc-557d526609b4", - "metadata": {}, - "source": [ - "Additional inputs to the LLM can be modified:\n", - "- tokens: the maximum number of tokens (words/sub-words) generated\n", - "- temperature: [0,1] -- higher values produce more diverse outputs\n", - "- [top_k](https://docs.cohere.com/docs/controlling-generation-with-top-k-top-p): sample from the k most likely next tokens at each step; lower value will concentrate sampling on the highest probability tokens for each step (reduces variety)\n", - "- [top_p](https://docs.cohere.com/docs/controlling-generation-with-top-k-top-p): [0, 1] -- cumulative probability cutoff for token selection; lower values mean sampling from a smaller nucleus sample (reduces variety)\n", - "- repetition_penalty: [1, 2] -- penalize repeated tokens\n", - "- length_penalty: 1 means no penalty for length of generation" - ] - }, - { - "cell_type": "markdown", - "id": "c526b20b-258a-4eb7-87e6-5430d57e32ea", - "metadata": {}, - "source": [ - "### Step 3: Load the Model and Stream Responses" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "274e4164-7460-4471-8625-90562237cf11", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "import random\n", - "\n", - "start_time = time.time()\n", - "tokens_generated = 0\n", - "\n", - "for val in client.stream(prompt):\n", - " tokens_generated += 1\n", - " print(val, end=\"\", flush=True)\n", - "\n", - "total_time = time.time() - start_time\n", - "print(f\"\\n--- Generated {tokens_generated} tokens in {total_time} seconds ---\")\n", - "print(f\"--- {tokens_generated/total_time} tokens/sec\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/05_dataloader.ipynb b/notebooks/01_dataloader.ipynb similarity index 100% rename from notebooks/05_dataloader.ipynb rename to notebooks/01_dataloader.ipynb diff --git a/notebooks/07_Option(1)_NVIDIA_AI_endpoint_simple.ipynb b/notebooks/02_Option(1)_NVIDIA_AI_endpoint_simple.ipynb old mode 100755 new mode 100644 similarity index 99% rename from notebooks/07_Option(1)_NVIDIA_AI_endpoint_simple.ipynb rename to notebooks/02_Option(1)_NVIDIA_AI_endpoint_simple.ipynb index 0ac07d54d..fdc1fb566 --- a/notebooks/07_Option(1)_NVIDIA_AI_endpoint_simple.ipynb +++ b/notebooks/02_Option(1)_NVIDIA_AI_endpoint_simple.ipynb @@ -78,7 +78,7 @@ "source": [ "# test run and see that you can genreate a respond successfully\n", "from langchain_nvidia_ai_endpoints import ChatNVIDIA\n", - " \n", + "\n", "llm = ChatNVIDIA(model=\"ai-mixtral-8x7b-instruct\", nvidia_api_key=nvapi_key, max_tokens=1024)\n", "\n", "result = llm.invoke(\"Write a ballad about LangChain.\")\n", @@ -114,7 +114,7 @@ "embedder = NVIDIAEmbeddings(model=\"ai-embed-qa-4\")\n", "\n", "# Alternatively, if you want to specify whether it will use the query or passage type\n", - "# embedder = NVIDIAEmbeddings(model=\"nvolveqa_40k\", model_type=\"passage\")" + "# embedder = NVIDIAEmbeddings(model=\"ai-embed-qa-4\", model_type=\"passage\")" ] }, { diff --git a/notebooks/07_Option(2)_minimalistic_RAG_with_langchain_local_HF_LLM.ipynb b/notebooks/02_Option(2)_minimalistic_RAG_with_langchain_local_HF_LLM.ipynb similarity index 100% rename from notebooks/07_Option(2)_minimalistic_RAG_with_langchain_local_HF_LLM.ipynb rename to notebooks/02_Option(2)_minimalistic_RAG_with_langchain_local_HF_LLM.ipynb diff --git a/notebooks/02_langchain_simple.ipynb b/notebooks/02_langchain_simple.ipynb deleted file mode 100644 index ec2f4a37f..000000000 --- a/notebooks/02_langchain_simple.ipynb +++ /dev/null @@ -1,346 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "0ffa8e4f", - "metadata": {}, - "source": [ - "# Q&A with LangChain\n", - "\n", - "This notebook demonstrates how to use LangChain to build a chatbot that references a custom knowledge-base. \n", - "\n", - "Suppose you have some text documents (PDF, blog, Notion pages, etc.) and want to ask questions related to the contents of those documents. LLMs, given their proficiency in understanding text, are a great tool for this. \n", - "\n", - "### [LangChain](https://python.langchain.com/docs/get_started/introduction)\n", - "[**LangChain**](https://python.langchain.com/docs/get_started/introduction) provides a simple framework for connecting LLMs to your own data sources. Since LLMs are both only trained up to a fixed point in time and do not contain knowledge that is proprietary to an Enterprise, they can't answer questions about new or proprietary knowledge. LangChain solves this problem.\n", - "\n", - "
\n", - " \n", - "⚠️ The notebook after this one, `03_llama_index_simple.ipynb`, contains the same functionality as this notebook but uses LlamaIndex instead of LangChain. Ultimately, we recommend reading about LangChain vs. LlamaIndex and picking the software/components of the software that makes the most sense to you. \n", - "\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "65082404", - "metadata": {}, - "source": [ - "![data_connection](./imgs/data_connection_langchain.jpeg)" - ] - }, - { - "cell_type": "markdown", - "id": "b0ea695d", - "metadata": {}, - "source": [ - "### Step 1: Integrate TensorRT-LLM to LangChain [*(Connector)*](https://docs.llamaindex.ai/en/stable/examples/llm/nvidia_tensorrt.html)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "f878600a", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_nvidia_trt.llms import TritonTensorRTLLM\n", - "\n", - "# Connect to the TRT-LLM Llama-2 model running on the Triton server at the url below\n", - "# Replace \"llm\" with the url of the system where llama2 is hosted\n", - "triton_url = \"llm:8001\"\n", - "pload = {\n", - " 'tokens':500,\n", - " 'server_url': triton_url,\n", - " 'model_name': \"ensemble\"\n", - "}\n", - "llm = TritonTensorRTLLM(**pload)" - ] - }, - { - "cell_type": "markdown", - "id": "d4ea84ce", - "metadata": {}, - "source": [ - "#### Note: Follow this step for nemotron models\n", - "1. In case you have deployed a trt-llm optimized nemotron model following steps [here](../RetrievalAugmentedGeneration/README.md#6-qa-chatbot----nemotron-model), execute the cell below by uncommenting the lines. Here we use a custom wrapper for talking with the model server." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1b35872", - "metadata": {}, - "outputs": [], - "source": [ - "# from triton_trt_llm import TensorRTLLM\n", - "# llm = TensorRTLLM(server_url =\"llm:8000\", model_name=\"ensemble\", tokens=500, streaming=False)" - ] - }, - { - "cell_type": "markdown", - "id": "da50462b", - "metadata": {}, - "source": [ - "### Step 2: Create a Prompt Template [*(Model I/O)*](https://python.langchain.com/docs/modules/model_io/)\n", - "\n", - "A [**prompt template**](https://python.langchain.com/docs/modules/model_io/prompts/prompt_templates/) is a common paradigm in LLM development. \n", - "\n", - "They are a pre-defined set of instructions provided to the LLM and guide the output produced by the model. They can contain few shot examples and guidance and are a quick way to engineer the responses from the LLM. Llama 2 accepts the [prompt format](https://huggingface.co/blog/llama2#how-to-prompt-llama-2) shown in `LLAMA_PROMPT_TEMPLATE`, which we manipulate to be constructed with:\n", - "- The system prompt\n", - "- The context\n", - "- The user's question\n", - "\n", - "Langchain allows you to [create custom wrappers for your LLM](https://python.langchain.com/docs/modules/model_io/models/llms/custom_llm) in case you want to use your own LLM or a different wrapper than the one that is supported in LangChain. Since we are using a custom Llama2 model hosted on Triton with TRT-LLM, we have written a custom wrapper for our LLM. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4d22c1c7", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.prompts import PromptTemplate\n", - "\n", - "LLAMA_PROMPT_TEMPLATE = (\n", - " \"[INST] <>\"\n", - " \"Use the following context to answer the user's question. If you don't know the answer, just say that you don't know, don't try to make up an answer.\"\n", - " \"<>\"\n", - " \"[INST] Context: {context} Question: {question} Only return the helpful answer below and nothing else. Helpful answer:[/INST]\"\n", - ")\n", - "\n", - "LLAMA_PROMPT = PromptTemplate.from_template(LLAMA_PROMPT_TEMPLATE)" - ] - }, - { - "cell_type": "markdown", - "id": "be6f97af", - "metadata": {}, - "source": [ - "### Step 3: Load Documents [*(Retrieval)*](https://python.langchain.com/docs/modules/data_connection/)\n", - "LangChain provides a variety of [document loaders](https://python.langchain.com/docs/integrations/document_loaders) that load various types of documents (HTML, PDF, code) from many different sources and locations (private s3 buckets, public websites).\n", - "\n", - "Document loaders load data from a source as **Documents**. A **Document** is a piece of text (the page_content) and associated metadata. Document loaders provide a ``load`` method for loading data as documents from a configured source. \n", - "\n", - "In this example, we use a LangChain [`UnstructuredFileLoader`](https://python.langchain.com/docs/integrations/document_loaders/unstructured_file) to load a research paper about Llama2 from Meta.\n", - "\n", - "[Here](https://python.langchain.com/docs/integrations/document_loaders) are some of the other document loaders available from LangChain." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a1377c60", - "metadata": {}, - "outputs": [], - "source": [ - "! wget -O \"llama2_paper.pdf\" -nc --user-agent=\"Mozilla\" https://arxiv.org/pdf/2307.09288.pdf" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "be053f41", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.document_loaders import UnstructuredFileLoader\n", - "loader = UnstructuredFileLoader(\"llama2_paper.pdf\")\n", - "data = loader.load()" - ] - }, - { - "cell_type": "markdown", - "id": "b909dd82", - "metadata": {}, - "source": [ - "### Step 4: Transform Documents [*(Retrieval)*](https://python.langchain.com/docs/modules/data_connection/)\n", - "Once documents have been loaded, they are often transformed. One method of transformation is known as **chunking**, which breaks down large pieces of text, for example, a long document, into smaller segments. This technique is valuable because it helps [optimize the relevance of the content returned from the vector database](https://www.pinecone.io/learn/chunking-strategies/). \n", - "\n", - "LangChain provides a [variety of document transformers](https://python.langchain.com/docs/integrations/document_transformers/), such as text splitters. In this example, we use a [``SentenceTransformersTokenTextSplitter``](https://api.python.langchain.com/en/latest/sentence_transformers/langchain_text_splitters.sentence_transformers.SentenceTransformersTokenTextSplitter.html). The ``SentenceTransformersTokenTextSplitter`` is a specialized text splitter for use with the sentence-transformer models. The default behaviour is to split the text into chunks that fit the token window of the sentence transformer model that you would like to use. This sentence transformer model is used to generate the embeddings from documents. \n", - "\n", - "There are some nuanced complexities to text splitting since semantically related text, in theory, should be kept together. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bfab1d35", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "from langchain.text_splitter import SentenceTransformersTokenTextSplitter\n", - "TEXT_SPLITTER_MODEL = \"intfloat/e5-large-v2\"\n", - "TEXT_SPLITTER_TOKENS_PER_CHUNK = 510\n", - "TEXT_SPLITTER_CHUNCK_OVERLAP = 200\n", - "\n", - "text_splitter = SentenceTransformersTokenTextSplitter(\n", - " model_name=TEXT_SPLITTER_MODEL,\n", - " tokens_per_chunk=TEXT_SPLITTER_TOKENS_PER_CHUNK,\n", - " chunk_overlap=TEXT_SPLITTER_CHUNCK_OVERLAP,\n", - ")\n", - "start_time = time.time()\n", - "documents = text_splitter.split_documents(data)\n", - "print(f\"--- {time.time() - start_time} seconds ---\")" - ] - }, - { - "cell_type": "markdown", - "id": "cbe64e4e", - "metadata": {}, - "source": [ - "Let's view a sample of content that is chunked together in the documents." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b48d697", - "metadata": {}, - "outputs": [], - "source": [ - "documents[40].page_content" - ] - }, - { - "cell_type": "markdown", - "id": "0243c9b5", - "metadata": {}, - "source": [ - "### Step 5: Generate Embeddings and Store Embeddings in the Vector Store [*(Retrieval)*](https://python.langchain.com/docs/modules/data_connection/)\n", - "\n", - "#### a) Generate Embeddings\n", - "[Embeddings](https://python.langchain.com/docs/modules/data_connection/text_embedding/) for documents are created by vectorizing the document text; this vectorization captures the semantic meaning of the text. This allows you to quickly and efficiently find other pieces of text that are similar. The embedding model used below is [intfloat/e5-large-v2](https://huggingface.co/intfloat/e5-large-v2).\n", - "\n", - "LangChain provides a wide variety of [embedding models](https://python.langchain.com/docs/integrations/text_embedding) from many providers and makes it simple to swap out the models. \n", - "\n", - "When a user sends in their query, the query is also embedded using the same embedding model that was used to embed the documents. As explained earlier, this allows to find similar (relevant) documents to the user's query. \n", - "\n", - "#### b) Store Document Embeddings in the Vector Store\n", - "Once the document embeddings are generated, they are stored in a vector store so that at query time we can:\n", - "1) Embed the user query and\n", - "2) Retrieve the embedding vectors that are most similar to the embedding query.\n", - "\n", - "A vector store takes care of storing the embedded data and performing a vector search.\n", - "\n", - "LangChain provides support for a [great selection of vector stores](https://python.langchain.com/docs/integrations/vectorstores/). \n", - "\n", - "
\n", - " \n", - "⚠️ For this workflow, [Milvus](https://milvus.io/) vector database is running as a microservice. \n", - "\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "88520151", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.embeddings import HuggingFaceEmbeddings\n", - "from langchain.vectorstores import Milvus\n", - "import torch\n", - "import time\n", - "\n", - "#Running the model on CPU as we want to conserve gpu memory.\n", - "#In the production deployment (API server shown as part of the 5th notebook we run the model on GPU)\n", - "model_name = \"intfloat/e5-large-v2\"\n", - "model_kwargs = {\"device\": \"cpu\"}\n", - "encode_kwargs = {\"normalize_embeddings\": False}\n", - "hf_embeddings = HuggingFaceEmbeddings(\n", - " model_name=model_name,\n", - " model_kwargs=model_kwargs,\n", - " encode_kwargs=encode_kwargs,\n", - ")\n", - "start_time = time.time()\n", - "vectorstore = Milvus.from_documents(documents=documents, embedding=hf_embeddings, connection_args={\"host\": \"milvus\", \"port\": \"19530\"})\n", - "print(f\"--- {time.time() - start_time} seconds ---\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59e4764f", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Simple Example: Retrieve Documents from the Vector Database\n", - "# note: this is just for demonstration purposes of a similarity search\n", - "question = \"Can you talk about safety evaluation of llama2 chat?\"\n", - "docs = vectorstore.similarity_search(question)\n", - "print(docs[2].page_content)" - ] - }, - { - "cell_type": "markdown", - "id": "352708d2", - "metadata": {}, - "source": [ - " > ### Simple Example: Retrieve Documents from the Vector Database [*(Retrieval)*](https://python.langchain.com/docs/modules/data_connection/)\n", - ">Given a user query, relevant splits for the question are returned through a **similarity search**. This is also known as a semantic search, and it is done with meaning. It is different from a lexical search, where the search engine looks for literal matches of the query words or variants of them, without understanding the overall meaning of the query. A semantic search tends to generate more relevant results than a lexical search.\n", - "![vector_stores.jpeg](./imgs/vector_stores.jpeg)" - ] - }, - { - "cell_type": "markdown", - "id": "50d81f63", - "metadata": {}, - "source": [ - "### Step 6: Compose a streamed answer using a Chain\n", - "We have already integrated the Llama2 TRT LLM with the help of LangChain connector, loaded and transformed documents, and generated and stored document embeddings in a vector database. To finish the pipeline, we need to add a few more LangChain components and combine all the components together with a [chain](https://python.langchain.com/docs/modules/chains/).\n", - "\n", - "A [LangChain chain](https://python.langchain.com/docs/modules/chains/) combines components together. In this case, we use [Langchain Expression Language](https://python.langchain.com/docs/expression_language/why) to build a chain.\n", - "\n", - "We formulate the prompt placeholders (context and question) and pipe it to our trt-llm connector as shown below and finally stream the result." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8bdb143b", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.runnables import RunnablePassthrough\n", - "import time\n", - "\n", - "chain = (\n", - " {\"context\": vectorstore.as_retriever(), \"question\": RunnablePassthrough()}\n", - " | LLAMA_PROMPT\n", - " | llm\n", - ")\n", - "start_time = time.time()\n", - "for token in chain.stream(question):\n", - " print(token, end=\"\", flush=True)\n", - "print(f\"\\n--- {time.time() - start_time} seconds ---\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/08_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb b/notebooks/03_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb old mode 100755 new mode 100644 similarity index 98% rename from notebooks/08_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb rename to notebooks/03_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb index f361a8c08..56769a71b --- a/notebooks/08_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb +++ b/notebooks/03_Option(1)_llama_index_with_NVIDIA_AI_endpoint.ipynb @@ -107,7 +107,7 @@ "nv_embedding = NVIDIAEmbeddings(model=\"ai-embed-qa-4\")\n", "li_embedding=LangchainEmbedding(nv_embedding)\n", "# Alternatively, if you want to specify whether it will use the query or passage type\n", - "# embedder = NVIDIAEmbeddings(model=\"nvolveqa_40k\", model_type=\"passage\")\n" + "# embedder = NVIDIAEmbeddings(model=\"ai-embed-qa-4\", model_type=\"passage\")\n" ] }, { diff --git a/notebooks/08_Option(2)_llama_index_with_HF_local_LLM.ipynb b/notebooks/03_Option(2)_llama_index_with_HF_local_LLM.ipynb similarity index 100% rename from notebooks/08_Option(2)_llama_index_with_HF_local_LLM.ipynb rename to notebooks/03_Option(2)_llama_index_with_HF_local_LLM.ipynb diff --git a/notebooks/03_llama_index_simple.ipynb b/notebooks/03_llama_index_simple.ipynb deleted file mode 100644 index 93f5749c7..000000000 --- a/notebooks/03_llama_index_simple.ipynb +++ /dev/null @@ -1,463 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d7bbdbd7", - "metadata": {}, - "source": [ - "# Q&A with LlamaIndex\n", - "\n", - "This notebook demonstrates how to use [LlamaIndex](https://docs.llamaindex.ai/en/stable/) to build a chatbot that references a custom knowledge base. \n", - "\n", - "Suppose you have some text documents (PDF, blog, Notion pages, etc.) and want to ask questions related to the contents of those documents. LLMs, given their proficiency in understanding text, are a great tool for this. \n", - "\n", - "
\n", - " \n", - "⚠️ The notebook before this one, `02_langchain_index_simple.ipynb`, contains the same functionality as this notebook but uses some LangChain components instead of LlamaIndex components. \n", - "\n", - "Concepts that are used in this notebook are explained in-depth in the previous notebook. If you are new to retrieval augmented generation, it is recommended to go through the previous notebook before this one. \n", - "\n", - "Ultimately, we recommend reading about LangChain vs. LlamaIndex and picking the software/components of the software that makes the most sense to you. This is discussed a bit further below. \n", - "\n", - "
\n", - "\n", - "### [LlamaIndex](https://docs.llamaindex.ai/en/stable/)\n", - "[**LlamaIndex**](https://docs.llamaindex.ai/en/stable/) is a data framework for LLM applications to ingest, structure, and access private or domain-specific data. Since LLMs are both only trained up to a fixed point in time and do not contain knowledge that is proprietary to an Enterprise, they can't answer questions about new or proprietary knowledge. LlamaIndex helps solve this problem by providing data connectors to ingest data, indices to structure data for storage, and engines to communicate with data. \n", - "\n", - "\n", - "### [LlamaIndex](https://docs.llamaindex.ai/en/stable/) or [LangChain](https://python.langchain.com/docs/get_started/introduction)?\n", - "\n", - "It's recommended to read more about the unique strengths of both LlamaIndex and LangChain. At a high level, LangChain is a more general framework for building applications with LLMs. LangChain is (currently) more mature when it comes to multi-step chains and some other chat functionality such as conversational memory. LlamaIndex has plenty of overlap with LangChain, but is particularly strong for loading data from a wide variety of sources and indexing/querying tasks. \n", - "\n", - "Since LlamaIndex can be used *with* LangChain, the frameworks' unique capabilities can be leveraged together; the combination of the two is demonstrated in this notebook.\n" - ] - }, - { - "cell_type": "markdown", - "id": "953946f1", - "metadata": {}, - "source": [ - "### Step 1: Integrate TensorRT-LLM to LangChain *and* LlamaIndex\n", - "#### Customized LangChain LLM in LlamaIndex\n", - "Langchain allows you to create custom wrappers for your LLM in case you want to use your own LLM or a different wrapper than the one that is supported in LangChain. Since we are using LlamaIndex, we have written a custom langchain wrapper compatible with LlamaIndex.\n", - "\n", - "We can easily take a custom LLM that has been wrapped for LangChain and plug it into [LlamaIndex as an LLM](https://docs.llamaindex.ai/en/stable/understanding/using_llms/using_llms.html#using-llms)! We use the [LlamaIndex LangChainLLM library](https://docs.llamaindex.ai/en/v0.9.48/api_reference/llms/langchain.html) so the LangChain LLM can be used in LlamaIndex. \n", - "\n", - "
\n", - " \n", - "WARNING! Be sure to replace `server_url` with the address and port that Triton is running on. \n", - "\n", - "
\n", - "\n", - "Use the address and port that the Triton is available on; for example `localhost:8001`. **If you are running this notebook as part of the generative ai workflow, your can use the existing url.**" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "7919fd82", - "metadata": {}, - "outputs": [], - "source": [ - "from triton_trt_llm import TensorRTLLM\n", - "from llama_index.llms import LangChainLLM\n", - "trtllm =TensorRTLLM(server_url =\"llm:8001\", model_name=\"ensemble\", tokens=500)\n", - "llm = LangChainLLM(llm=trtllm)" - ] - }, - { - "cell_type": "markdown", - "id": "18600300", - "metadata": {}, - "source": [ - "### Step 2: Create a Prompt Template\n", - "\n", - "A [**prompt template**](https://docs.llamaindex.ai/en/stable/module_guides/models/prompts.html) is a common paradigm in LLM development.\n", - "\n", - "They are a pre-defined set of instructions provided to the LLM and guide the output produced by the model. They can contain few shot examples and guidance and are a quick way to engineer the responses from the LLM. Llama 2 accepts the [prompt format](https://huggingface.co/blog/llama2#how-to-prompt-llama-2) shown in `LLAMA_PROMPT_TEMPLATE`, which we manipulate to be constructed with:\n", - "- The system prompt\n", - "- The context\n", - "- The user's question\n", - " \n", - "Much like LangChain's abstraction of prompts, LlamaIndex has similar abstractions for you to create prompts." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "4fa60e49", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import Prompt\n", - "\n", - "LLAMA_PROMPT_TEMPLATE = (\n", - " \"[INST] <>\"\n", - " \"Use the following context to answer the user's question. If you don't know the answer, just say that you don't know, don't try to make up an answer.\"\n", - " \"<>\"\n", - " \"[INST] Context: {context_str} Question: {query_str} Only return the helpful answer below and nothing else. Helpful answer:[/INST]\"\n", - ")\n", - "\n", - "qa_template = Prompt(LLAMA_PROMPT_TEMPLATE)" - ] - }, - { - "cell_type": "markdown", - "id": "6063c0e0", - "metadata": {}, - "source": [ - "### Step 3: Load Documents\n", - "\n", - "
\n", - "\n", - "
\n", - "\n", - "LlamaIndex provides [**data loaders**](https://docs.llamaindex.ai/en/stable/module_guides/loading/connector/root.html#data-connectors-llamahub) through Llama Hub.\n", - "These allow for custom data sources to be connected to your LLM using integrations.\n", - "For example, integrations are available to load documents from\n", - "Jira,\n", - "Outlook Calendar,\n", - "Slack,\n", - "Trello, and many other applications. \n", - "\n", - "At the core of each data loader is a `download_loader` function which downloads the loader file into a module that you can use in your application. Once the loader is downloaded, data is ingested through the loader. The output of this ingestion is data formatted as a LlamaIndex [**Document**](https://docs.llamaindex.ai/en/stable/module_guides/loading/documents_and_nodes/root.html#documents-nodes) (text and metadata). \n", - "\n", - "Similar to the previous notebook with LangChain, an [`UnstructuredReader`](https://llamahub.ai/l/readers/llama-index-readers-file) is used in this example. However, this time it's from from [Llama Hub](https://llamahub.ai/) (LlamaIndex). Again, we load a research paper about Llama2 from Meta. \n", - "\n", - "[Here](https://python.langchain.com/docs/integrations/document_loaders) are some of the other document loaders available from LangChain." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "4f14d618", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "File ‘llama2_paper.pdf’ already there; not retrieving.\n" - ] - } - ], - "source": [ - "! wget -O \"llama2_paper.pdf\" -nc --user-agent=\"Mozilla\" https://arxiv.org/pdf/2307.09288.pdf" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "81fe0d1c", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[nltk_data] Downloading package punkt to /root/nltk_data...\n", - "[nltk_data] Package punkt is already up-to-date!\n", - "[nltk_data] Downloading package averaged_perceptron_tagger to\n", - "[nltk_data] /root/nltk_data...\n", - "[nltk_data] Package averaged_perceptron_tagger is already up-to-\n", - "[nltk_data] date!\n" - ] - } - ], - "source": [ - "from llama_hub.file.unstructured.base import UnstructuredReader\n", - "import time\n", - "\n", - "loader = UnstructuredReader()\n", - "start_time = time.time()\n", - "documents = loader.load_data(file=\"llama2_paper.pdf\")\n", - "print(f\"--- {time.time() - start_time} seconds ---\")" - ] - }, - { - "cell_type": "markdown", - "id": "068e61bd", - "metadata": {}, - "source": [ - "### Step 4: Transform Documents with Text Splitting and a Node Parser\n", - "#### a) Generate Embeddings \n", - "Once documents have been loaded, they are often transformed. One method of transformation is known as **chunking**, which breaks down large pieces of text, for example, a long document, into smaller segments. This technique is valuable because it helps [optimize the relevance of the content returned from the vector database](https://www.pinecone.io/learn/chunking-strategies/). \n", - "\n", - "This is the same process as the previous notebook; again, we use a LangChain text splitter. In this example, we use a [``SentenceTransformersTokenTextSplitter``](https://api.python.langchain.com/en/latest/sentence_transformers/langchain_text_splitters.sentence_transformers.SentenceTransformersTokenTextSplitter.html). The ``SentenceTransformersTokenTextSplitter`` is a specialized text splitter for use with the sentence-transformer models. The default behavior is to split the text into chunks that fit the token window of the sentence transformer model that you would like to use. This sentence transformer model is used to generate the embeddings from documents.\n", - "\n", - "There are some nuanced complexities to text splitting since semantically related text, in theory, should be kept together. \n", - "\n", - "To use the Langchain's `SentenceTransformersTokenTextSplitter` with LlamaIndex we use the [**Langchain node parser**](https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/modules.html#langchainnodeparser) on top of the text splitter from LangChain. This is not required, but since LlamaIndex provides a [**node structure**](https://docs.llamaindex.ai/en/stable/module_guides/loading/documents_and_nodes/root.html#documents-nodes), we choose to use this functionality to level up our storage of documents. \n", - "\n", - "**Nodes** represent chunks of source documents, but they also contain metadata and relationship information with other nodes and index structures. Since nodes provide these additional forms of hierarchy and connections across the data, they can help generate more accurate answers upon retrieval." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "cdcd2b05", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - } - ], - "source": [ - "from langchain.text_splitter import SentenceTransformersTokenTextSplitter\n", - "from llama_index.node_parser import LangchainNodeParser\n", - "\n", - "\n", - "TEXT_SPLITTER_MODEL = \"intfloat/e5-large-v2\"\n", - "TEXT_SPLITTER_TOKENS_PER_CHUNK = 510\n", - "TEXT_SPLITTER_CHUNCK_OVERLAP = 200\n", - "\n", - "text_splitter = SentenceTransformersTokenTextSplitter(\n", - " model_name=TEXT_SPLITTER_MODEL,\n", - " tokens_per_chunk=TEXT_SPLITTER_TOKENS_PER_CHUNK,\n", - " chunk_overlap=TEXT_SPLITTER_CHUNCK_OVERLAP,\n", - ")\n", - "\n", - "node_parser = LangchainNodeParser(text_splitter)" - ] - }, - { - "cell_type": "markdown", - "id": "2b27c7b7", - "metadata": {}, - "source": [ - "Additionally, we use a LlamaIndex [``PromptHelper``](https://docs.llamaindex.ai/en/stable/api_reference/service_context/prompt_helper.html) to help deal with LLM context window token limitations. It calculates available context size to the LLM by taking the initial context token length and subtracting out reserved token space for the prompt template and output. It provides a utility for re-packing text chunks from the index to maximally use the context window to minimize requests sent to the LLM.\n", - "\n", - "- ``context_window``: context window for the LLM -- the context length for Llama2 is 4k tokens\n", - "- ``num_ouptut``: number of output tokens for the LLM\n", - "- ``chunk_overlap_ratio``: chunk overlap as a ratio to chunk size\n", - "- ``chunk_size_limit``: maximum chunk size to use" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "1f429667", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import PromptHelper\n", - "\n", - "prompt_helper = PromptHelper(\n", - " context_window=4096,\n", - " num_output=256,\n", - " chunk_overlap_ratio=0.1,\n", - " chunk_size_limit=None\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "ca97830a", - "metadata": {}, - "source": [ - "### Step 5: Generate and Store Embeddings\n", - "#### a) Generate Embeddings \n", - "[Embeddings](https://docs.llamaindex.ai/en/stable/module_guides/models/embeddings.html#embeddings) for documents are created by vectorizing the document text; this vectorization captures the semantic meaning of the text. This allows you to quickly and efficiently find other pieces of text that are similar. \n", - "\n", - "When a user sends in their query, the query is also embedded using the same embedding model that was used to embed the documents. As explained earlier, this allows us to find similar (relevant) documents to the user's query. \n", - "\n", - "Like other sections in this notebook, we can easily take a LangChain embedding object and use with LlamaIndex. We use the [LangchainEmbedding library](https://docs.llamaindex.ai/en/stable/api_reference/service_context/embeddings.html#langchainembedding), which acts as a wrapper around Langchain's embedding models. " - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "0fa4c0fd", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.embeddings import HuggingFaceEmbeddings\n", - "from llama_index.embeddings import LangchainEmbedding\n", - "\n", - "#Running the model on CPU as we want to conserve gpu memory.\n", - "#In the production deployment (API server shown as part of the 5th notebook we run the model on GPU)\n", - "model_name=\"intfloat/e5-large-v2\"\n", - "model_kwargs = {\"device\": \"cpu\"}\n", - "encode_kwargs = {\"normalize_embeddings\": False}\n", - "hf_embeddings = HuggingFaceEmbeddings(\n", - " model_name=model_name,\n", - " model_kwargs=model_kwargs,\n", - " encode_kwargs=encode_kwargs,\n", - ")\n", - "# Load in a specific embedding model\n", - "embed_model = LangchainEmbedding(hf_embeddings)" - ] - }, - { - "cell_type": "markdown", - "id": "22aa461b", - "metadata": {}, - "source": [ - "#### b) Store Embeddings \n", - "\n", - "LlamaIndex provides a supporting module, [`ServiceContext`](https://docs.llamaindex.ai/en/v0.10.19/api_reference/service_context.html), to bundle commonly used resources during the indexing and querying stage. In this example, we bundle resources we've built: the LLM, the embedding model, the node parser, and the prompt helper. " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "4a11b80f", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import ServiceContext\n", - "service_context = ServiceContext.from_defaults(\n", - " llm=llm,\n", - " embed_model=embed_model,\n", - " node_parser=node_parser,\n", - " prompt_helper=prompt_helper\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "c14162d7", - "metadata": {}, - "source": [ - "Set the service context globally, to avoid passing it to every llm call/" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "48d000dd", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import set_global_service_context\n", - "set_global_service_context(service_context)" - ] - }, - { - "cell_type": "markdown", - "id": "7584850f", - "metadata": {}, - "source": [ - "
\n", - " \n", - "⚠️ in the deployment of this workflow, [Milvus](https://milvus.io/) is running as a vector database microservice.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "50b5fbfc", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import VectorStoreIndex\n", - "from llama_index.storage.storage_context import StorageContext\n", - "from llama_index.vector_stores import MilvusVectorStore\n", - "\n", - "vector_store = MilvusVectorStore(uri=\"http://milvus:19530\", dim=1024, overwrite=False)\n", - "storage_context = StorageContext.from_defaults(vector_store=vector_store)\n", - "index = VectorStoreIndex.from_vector_store(vector_store)" - ] - }, - { - "cell_type": "markdown", - "id": "6af82726", - "metadata": {}, - "source": [ - "Let's load the documents into the vector database index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b49c4acf", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "start_time = time.time()\n", - "nodes = node_parser.get_nodes_from_documents(documents)\n", - "index.insert_nodes(nodes)\n", - "print(f\"--- {time.time() - start_time} seconds ---\")" - ] - }, - { - "cell_type": "markdown", - "id": "126cda61", - "metadata": {}, - "source": [ - "### Step 6: Build the Query Engine and Stream Response\n", - "\n", - "#### a) Build the Query Engine\n", - "\n", - "A query engine is an object that takes in a query and returns a response. Each vector index has a default corresponding query engine; for example, the default query engine for a vector index performs a standard top-k retrieval over the vector store.\n", - "\n", - "A query engine contains the following components:\n", - "- Retriever\n", - "- Node PostProcessor\n", - "- Response Synthesizer " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cd24b951", - "metadata": {}, - "outputs": [], - "source": [ - "query_engine = index.as_query_engine(text_qa_template=qa_template, streaming=True)" - ] - }, - { - "cell_type": "markdown", - "id": "90b61943", - "metadata": {}, - "source": [ - "#### b) Stream a Response from the Query Engine\n", - "Lastly, we pass the query engine a user's question and stream the response. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "97a018d6", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "\n", - "start_time = time.time()\n", - "response = query_engine.query(\"what is the context length of llama2?\")\n", - "response.print_response_stream()\n", - "print(f\"\\n--- {time.time() - start_time} seconds ---\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/09_Agent_use_tools_leveraging_NVIDIA_AI_endpoints.ipynb b/notebooks/04_Agent_use_tools_leveraging_NVIDIA_AI_endpoints.ipynb similarity index 100% rename from notebooks/09_Agent_use_tools_leveraging_NVIDIA_AI_endpoints.ipynb rename to notebooks/04_Agent_use_tools_leveraging_NVIDIA_AI_endpoints.ipynb diff --git a/notebooks/04_llamaindex_hier_node_parser.ipynb b/notebooks/04_llamaindex_hier_node_parser.ipynb deleted file mode 100644 index 100ac1dd5..000000000 --- a/notebooks/04_llamaindex_hier_node_parser.ipynb +++ /dev/null @@ -1,463 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "be350003", - "metadata": {}, - "source": [ - "# Advanced Q&A with LlamaIndex\n", - "\n", - "This notebook demonstrates how to use [LlamaIndex](https://docs.llamaindex.ai/en/stable/) to build a more complex retrieval for a chatbot. \n", - "\n", - "The retrieval method shown in this notebook works well for code documentation; it retrieves more contiguous document blocks that preserve both code snippets and explanations of code. \n", - "\n", - "
\n", - " \n", - "⚠️ There are many node parsing and retrieval techniques supported in LlamaIndex and this notebook just shows how two of these techniques, [HierarchialNodeParser](https://docs.llamaindex.ai/en/stable/api_reference/service_context/node_parser.html) and [AutoMergingRetriever](https://docs.llamaindex.ai/en/stable/examples/retrievers/auto_merging_retriever.html), can be useful for chatting with code documentation. \n", - "
\n", - "\n", - "In this demo, we'll use the [`llama_docs_bot`](https://github.com/run-llama/llama_docs_bot/tree/main) GitHub repository as our sample documentation to query. This repository contains the content for a development series with LlamaIndex covering the following topics: \n", - "- LLMs\n", - "- Nodes and documents\n", - "- Evaluation\n", - "- Embeddings\n", - "- Retrieval" - ] - }, - { - "cell_type": "markdown", - "id": "547a35c9", - "metadata": {}, - "source": [ - "### Step 1: Prerequisite Setup\n", - "By now you should be familiar with these steps:\n", - "1. Create an LLM client.\n", - "2. Set the prompt template for the LLM.\n", - "3. Download embeddings.\n", - "4. Set the service context.\n", - "5. Split the text\n", - "\n", - "
\n", - " \n", - "WARNING! Be sure to replace `server_url` with the address and port that Triton is running on. \n", - "\n", - "
\n", - "\n", - "Use the address and port that the Triton is available on; for example `localhost:8001`. **If you are running this notebook as part of the generative ai workflow, you can use the existing url." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "df278873", - "metadata": {}, - "outputs": [], - "source": [ - "from triton_trt_llm import TensorRTLLM\n", - "from llama_index.llms import LangChainLLM\n", - "trtllm =TensorRTLLM(server_url =\"llm:8001\", model_name=\"ensemble\", tokens=500)\n", - "llm = LangChainLLM(llm=trtllm)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "80b01c15", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import Prompt\n", - "\n", - "LLAMA_PROMPT_TEMPLATE = (\n", - " \"[INST] <>\"\n", - " \"Use the following context to answer the user's question. If you don't know the answer, just say that you don't know, don't try to make up an answer.\"\n", - " \"<>\"\n", - " \"[INST] Context: {context_str} Question: {query_str} Only return the helpful answer below and nothing else. Helpful answer:[/INST]\"\n", - ")\n", - "\n", - "qa_template = Prompt(LLAMA_PROMPT_TEMPLATE)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "30d8fb1e", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.embeddings import HuggingFaceEmbeddings\n", - "from llama_index.embeddings import LangchainEmbedding\n", - "from llama_index import ServiceContext, set_global_service_context\n", - "\n", - "model_kwargs = {\"device\": \"cpu\"}\n", - "encode_kwargs = {\"normalize_embeddings\": False}\n", - "hf_embeddings = HuggingFaceEmbeddings(\n", - " model_name=\"intfloat/e5-large-v2\",\n", - " model_kwargs=model_kwargs,\n", - " encode_kwargs=encode_kwargs,\n", - ")\n", - "# Load in a specific embedding model\n", - "embed_model = LangchainEmbedding(hf_embeddings)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c47d0437", - "metadata": {}, - "outputs": [], - "source": [ - "service_context = ServiceContext.from_defaults(\n", - " llm=llm,\n", - " embed_model=embed_model\n", - ")\n", - "set_global_service_context(service_context)" - ] - }, - { - "cell_type": "markdown", - "id": "eb9b7488", - "metadata": {}, - "source": [ - "When splitting the text, we split it into a parent node of 1024 tokens and two children nodes of 510 tokens. Our leaf nodes' maximum size is 512 tokens, so we need to make the largest leaves that can exist under 512 tokens. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "797170a7", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index.text_splitter import TokenTextSplitter\n", - "text_splitter_ids = [\"1024\", \"510\"]\n", - "text_splitter_map = {}\n", - "for ids in text_splitter_ids:\n", - " text_splitter_map[ids] = TokenTextSplitter(\n", - " chunk_size=int(ids),\n", - " chunk_overlap=200\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "c1395c0e", - "metadata": {}, - "source": [ - "### Step 2: Clone the Llama Docs Bot Repo \n", - "This repository will be our sample documentation that we chat with. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bbf2a3ae", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "!git clone https://github.com/run-llama/llama_docs_bot.git" - ] - }, - { - "cell_type": "markdown", - "id": "e977334a", - "metadata": {}, - "source": [ - "### Step 3: Define Document Loading and Node Parsing Function\n", - "\n", - "Assuming hierarchical node parsing is set to true, this function:\n", - "- Parses each directory into a single giant document\n", - "- Chunks the document into a hierarchy of nodes with a top-level chunk size (1024) and children chunks that are smaller (aka **hierarchical node parsing**)\n", - " ```\n", - " 1024\n", - " /--------\\\n", - " 1024//2 1024//2\n", - "\n", - " ```\n", - "\n", - "#### Hierarchical Node Parser\n", - "The novel part of this step is using LlamaIndex's [**Hierarchical Node Parser**](https://docs.llamaindex.ai/en/stable/api/llama_index.core.node_parser.HierarchicalNodeParser.html#llama_index.core.node_parser.HierarchicalNodeParser). This parses nodes into several chunk sizes. \n", - "\n", - "During retrieval, if a majority of chunks are retrieved that have the same parent chunk, the larger parent chunk is returned instead of the smaller chunks.\n", - "\n", - "#### Simple Node Parser\n", - "If hierarchical parsing is false, a simple node structure is used and returned." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cff5b264", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import SimpleDirectoryReader, Document\n", - "from llama_index.node_parser import HierarchicalNodeParser, SimpleNodeParser, get_leaf_nodes\n", - "from llama_index.schema import MetadataMode\n", - "from llama_docs_bot.llama_docs_bot.markdown_docs_reader import MarkdownDocsReader\n", - "\n", - "# This function takes in a directory of files, puts them in a giant document, and parses and returns them as:\n", - "# - a hierarchical node structure if it's a hierarchical implementation\n", - "# - a simple node structure if it's a non-hierarchial implementation\n", - "def load_markdown_docs(filepath, hierarchical=True):\n", - " \"\"\"Load markdown docs from a directory, excluding all other file types.\"\"\"\n", - " loader = SimpleDirectoryReader(\n", - " input_dir=filepath,\n", - " required_exts=[\".md\"],\n", - " file_extractor={\".md\": MarkdownDocsReader()},\n", - " recursive=True\n", - " )\n", - "\n", - " documents = loader.load_data()\n", - "\n", - " if hierarchical:\n", - " # combine all documents into one\n", - " documents = [\n", - " Document(text=\"\\n\\n\".join(\n", - " document.get_content(metadata_mode=MetadataMode.ALL)\n", - " for document in documents\n", - " )\n", - " )\n", - " ]\n", - "\n", - " # chunk into 3 levels\n", - " # majority means 2/3 are retrieved before using the parent\n", - " large_chunk_size = 1536\n", - " node_parser = HierarchicalNodeParser.from_defaults(node_parser_ids=text_splitter_ids, node_parser_map=text_splitter_map)\n", - "\n", - " nodes = node_parser.get_nodes_from_documents(documents)\n", - " return nodes, get_leaf_nodes(nodes)\n", - " ########## This is NOT a hierarchical parser for demonstration purposes later in the notebook ##########\n", - " else:\n", - " node_parser = SimpleNodeParser.from_defaults()\n", - " nodes = node_parser.get_nodes_from_documents(documents)\n", - " return nodes" - ] - }, - { - "cell_type": "markdown", - "id": "3905a5b6", - "metadata": {}, - "source": [ - "### Step 4: Load and Parse Documents with Node Parser \n", - "\n", - "First, we define all of the documentation directories we want to pull from. \n", - "\n", - "Next, we load the documentation and store parent nodes in a `SimpleDocumentStore` and leaf nodes in a `VectorStoreIndex`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6311a28d", - "metadata": {}, - "outputs": [], - "source": [ - "docs_directories = {\n", - " \"./llama_docs_bot/docs/community\": \"Useful for information on community integrations with other libraries, vector dbs, and frameworks.\",\n", - " \"./llama_docs_bot/docs/core_modules/agent_modules\": \"Useful for information on data agents and tools for data agents.\",\n", - " \"./llama_docs_bot/docs/core_modules/data_modules\": \"Useful for information on data, storage, indexing, and data processing modules.\",\n", - " \"./llama_docs_bot/docs/core_modules/model_modules\": \"Useful for information on LLMs, embedding models, and prompts.\",\n", - " \"./llama_docs_bot/docs/core_modules/query_modules\": \"Useful for information on various query engines and retrievers, and anything related to querying data.\",\n", - " \"./llama_docs_bot/docs/core_modules/supporting_modules\": \"Useful for information on supporting modules, like callbacks, evaluators, and other supporting modules.\",\n", - " \"./llama_docs_bot/docs/getting_started\": \"Useful for information on getting started with LlamaIndex.\",\n", - " \"./llama_docs_bot/docs/development\": \"Useful for information on contributing to LlamaIndex development.\",\n", - "}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6ef673e8", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index import VectorStoreIndex,StorageContext, load_index_from_storage\n", - "from llama_index.query_engine import RetrieverQueryEngine\n", - "\n", - "from llama_index.tools import QueryEngineTool, ToolMetadata\n", - "from llama_index.storage.docstore import SimpleDocumentStore\n", - "import os\n", - "import time\n", - "\n", - "start_time = time.time()\n", - "for directory, description in docs_directories.items():\n", - " nodes, leaf_nodes = load_markdown_docs(directory, hierarchical=True)\n", - "\n", - " docstore = SimpleDocumentStore()\n", - " docstore.add_documents(nodes)\n", - " storage_context = StorageContext.from_defaults(docstore=docstore)\n", - "\n", - " index = VectorStoreIndex(leaf_nodes, storage_context=storage_context)\n", - " index.storage_context.persist(persist_dir=f\"./data_{os.path.basename(directory)}\")\n", - "\n", - "print(f\"--- {time.time() - start_time} seconds ---\")" - ] - }, - { - "cell_type": "markdown", - "id": "511e1c67", - "metadata": {}, - "source": [ - "### Step 5: Define Custom Node Post-Processor\n", - "\n", - "A [**Node PostProcessor**](https://docs.llamaindex.ai/en/stable/module_guides/querying/node_postprocessors/node_postprocessors.html#node-postprocessor-modules) takes a list of retrieved nodes and transforms them (filtering, replacement, etc). \n", - "\n", - "This custom node post-processor provides a simple approach to approximate token counts and returns the most nodes that fit within the token count (2500 tokens). Nodes are already sorted, so the most similar ones are returned first. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "546442b4", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Callable, Optional\n", - "\n", - "from llama_index.utils import globals_helper, get_tokenizer\n", - "from llama_index.schema import MetadataMode\n", - "\n", - "class LimitRetrievedNodesLength:\n", - "\n", - " def __init__(self, limit: int = 2500, tokenizer: Optional[Callable] = None):\n", - " self._tokenizer = tokenizer or get_tokenizer()\n", - "\n", - " self.limit = limit\n", - "\n", - " def postprocess_nodes(self, nodes, query_bundle):\n", - " included_nodes = []\n", - " current_length = 0\n", - "\n", - " for node in nodes:\n", - " current_length += len(self._tokenizer(node.node.get_content(metadata_mode=MetadataMode.LLM)))\n", - " if current_length > self.limit:\n", - " break\n", - " included_nodes.append(node)\n", - "\n", - " return included_nodes" - ] - }, - { - "cell_type": "markdown", - "id": "1fbddf64", - "metadata": {}, - "source": [ - "### Step 5: Build the Retriever and Query Engine\n", - "\n", - "#### AutoMergingRetriever\n", - "The [`AutoMergingRetriever`](https://docs.llamaindex.ai/en/stable/examples/retrievers/auto_merging_retriever.html) takes in a set of leaf nodes and recursively merges subsets of leaf nodes that reference a parent node beyond a given threshold. This allows for a consolidation of potentially disparate, smaller contexts into a larger context that may help synthesize disparate information. \n", - "\n", - "#### Query Engine\n", - "A query engine is an object that takes in a query and returns a response.\n", - "\n", - "It may contain the following components:\n", - "- **Retriever**: Given a query, retrieves relevant nodes.\n", - " - This example uses an `AutoMergingRetriever` if it's a hierarchial implementation.\n", - " *This replaces the retrieved nodes with the larger parent chunk*. \n", - "- **Node PostProcessor**: Takes a list of retrieved nodes and transforms them (filtering, replacement, etc.)\n", - " - This example uses a post-processor that filters the retrieved nodes to a limited length. \n", - "- **Response Synthesizer**: Takes a list of relevant nodes and synthesizes a response with an LLM." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a76d6820", - "metadata": {}, - "outputs": [], - "source": [ - "from llama_index.retrievers import AutoMergingRetriever\n", - "from llama_index.query_engine import RetrieverQueryEngine\n", - "\n", - "retriever = AutoMergingRetriever(\n", - " index.as_retriever(similarity_top_k=12),\n", - " storage_context=storage_context\n", - " )\n", - "\n", - "query_engine = RetrieverQueryEngine.from_args(\n", - " retriever,\n", - " text_qa_template=qa_template,\n", - " node_postprocessors=[LimitRetrievedNodesLength(limit=2500)],\n", - " streaming=True\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "b294862c", - "metadata": {}, - "source": [ - "### Step 6: Stream Response" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "695a42a1", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"How do I setup a weaviate vector db? Give me a code sample please.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7b319f0c", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import time\n", - "\n", - "start_time = time.time()\n", - "response = query_engine.query(query)\n", - "response.print_response_stream()\n", - "print(f\"\\n--- {time.time() - start_time} seconds ---\")" - ] - }, - { - "cell_type": "markdown", - "id": "5ec1e497", - "metadata": {}, - "source": [ - "To clear out cached data run:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9892b18a", - "metadata": {}, - "outputs": [], - "source": [ - "!rm -rf data_*" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/10_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb b/notebooks/05_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb similarity index 55% rename from notebooks/10_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb rename to notebooks/05_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb index 2a9202fcc..2f945afbb 100644 --- a/notebooks/10_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb +++ b/notebooks/05_RAG_for_HTML_docs_with_Langchain_NVIDIA_AI_Endpoints.ipynb @@ -32,92 +32,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "fd4dcc8b", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.com\n", - "Requirement already satisfied: langchain in /usr/local/lib/python3.10/dist-packages (0.1.9)\n", - "Requirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (6.0)\n", - "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.0.29)\n", - "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (3.9.3)\n", - "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (4.0.2)\n", - "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.6.4)\n", - "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.33)\n", - "Requirement already satisfied: langchain-community<0.1,>=0.0.21 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.0.26)\n", - "Requirement already satisfied: langchain-core<0.2,>=0.1.26 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.1.29)\n", - "Requirement already satisfied: langsmith<0.2.0,>=0.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.1.39)\n", - "Requirement already satisfied: numpy<2,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.22.2)\n", - "Requirement already satisfied: pydantic<3,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.10.7)\n", - "Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.31.0)\n", - "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (8.2.3)\n", - "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.1)\n", - "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (23.1.0)\n", - "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.3)\n", - "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.0.4)\n", - "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.9.2)\n", - "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in /usr/local/lib/python3.10/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (3.21.1)\n", - "Requirement already satisfied: typing-inspect<1,>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (0.9.0)\n", - "Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.10/dist-packages (from jsonpatch<2.0,>=1.33->langchain) (2.4)\n", - "Requirement already satisfied: anyio<5,>=3 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2,>=0.1.26->langchain) (3.7.1)\n", - "Requirement already satisfied: packaging<24.0,>=23.2 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2,>=0.1.26->langchain) (23.2)\n", - "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in /usr/local/lib/python3.10/dist-packages (from langsmith<0.2.0,>=0.1.0->langchain) (3.10.0)\n", - "Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (4.10.0)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.1.0)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.4)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2.2.1)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2022.12.7)\n", - "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy<3,>=1.4->langchain) (3.0.3)\n", - "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2,>=0.1.26->langchain) (1.3.1)\n", - "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2,>=0.1.26->langchain) (1.1.1)\n", - "Requirement already satisfied: mypy-extensions>=0.3.0 in /usr/local/lib/python3.10/dist-packages (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain) (1.0.0)\n", - "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", - "\u001b[0mLooking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.com\n", - "Requirement already satisfied: langchain_nvidia_ai_endpoints in /usr/local/lib/python3.10/dist-packages (0.0.4)\n", - "Requirement already satisfied: aiohttp<4.0.0,>=3.9.1 in /usr/local/lib/python3.10/dist-packages (from langchain_nvidia_ai_endpoints) (3.9.3)\n", - "Requirement already satisfied: langchain-core<0.2.0,>=0.1.5 in /usr/local/lib/python3.10/dist-packages (from langchain_nvidia_ai_endpoints) (0.1.29)\n", - "Requirement already satisfied: pillow<11.0.0,>=10.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain_nvidia_ai_endpoints) (10.3.0)\n", - "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.9.1->langchain_nvidia_ai_endpoints) (1.3.1)\n", - "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.9.1->langchain_nvidia_ai_endpoints) (23.1.0)\n", - "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.9.1->langchain_nvidia_ai_endpoints) (1.3.3)\n", - "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.9.1->langchain_nvidia_ai_endpoints) (6.0.4)\n", - "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.9.1->langchain_nvidia_ai_endpoints) (1.9.2)\n", - "Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.9.1->langchain_nvidia_ai_endpoints) (4.0.2)\n", - "Requirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (6.0)\n", - "Requirement already satisfied: anyio<5,>=3 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (3.7.1)\n", - "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (1.33)\n", - "Requirement already satisfied: langsmith<0.2.0,>=0.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (0.1.39)\n", - "Requirement already satisfied: packaging<24.0,>=23.2 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (23.2)\n", - "Requirement already satisfied: pydantic<3,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (1.10.7)\n", - "Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (2.31.0)\n", - "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (8.2.3)\n", - "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (3.4)\n", - "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (1.3.1)\n", - "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (1.1.1)\n", - "Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.10/dist-packages (from jsonpatch<2.0,>=1.33->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (2.4)\n", - "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in /usr/local/lib/python3.10/dist-packages (from langsmith<0.2.0,>=0.1.0->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (3.10.0)\n", - "Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (4.10.0)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (3.1.0)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (2.2.1)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain-core<0.2.0,>=0.1.5->langchain_nvidia_ai_endpoints) (2022.12.7)\n", - "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", - "\u001b[0mLooking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.com\n", - "Collecting faiss-cpu\n", - " Downloading faiss_cpu-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.6 kB)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from faiss-cpu) (1.22.2)\n", - "Downloading faiss_cpu-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (27.0 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m27.0/27.0 MB\u001b[0m \u001b[31m16.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n", - "\u001b[?25hInstalling collected packages: faiss-cpu\n", - "Successfully installed faiss-cpu-1.8.0\n", - "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", - "\u001b[0m" - ] - } - ], + "outputs": [], "source": [ "!pip install langchain\n", "!pip install langchain_nvidia_ai_endpoints\n", @@ -157,7 +75,7 @@ "metadata": {}, "outputs": [ { - "name": "stdin", + "name": "stdout", "output_type": "stream", "text": [ "Enter your NVIDIA API key: ······································································\n" @@ -243,7 +161,7 @@ "Read html files and split text in preparation for embedding generation\n", "Note chunk_size value must match the specific LLM used for embedding genetation\n", "\n", - "Make sure to pay attention to the chunk_size parameter in TextSplitter. Setting the right chunk size is critical for RAG performance, as much of a RAG’s success is based on the retrieval step finding the right context for generation. The entire prompt (retrieved chunks + user query) must fit within the LLM’s context window. Therefore, you should not specify chunk sizes too big, and balance them out with the estimated query size. For example, while OpenAI LLMs have a context window of 8k-32k tokens, Llama2 is limited to 4k tokens. Experiment with different chunk sizes, but typical values should be 100-600, depending on the LLM." + "Make sure to pay attention to the chunk_size parameter in TextSplitter. Setting the right chunk size is critical for RAG performance, as much of a RAG’s success is based on the retrieval step finding the right context for generation. The entire prompt (retrieved chunks + user query) must fit within the LLM’s context window. Therefore, you should not specify chunk sizes too big, and balance them out with the estimated query size. For example, while OpenAI LLMs have a context window of 8k-32k tokens, Llama3 is limited to 8k tokens. Experiment with different chunk sizes, but typical values should be 100-600, depending on the LLM." ] }, { @@ -311,8 +229,8 @@ " Returns:\n", " None\n", " \"\"\"\n", - " embeddings = NVIDIAEmbeddings(model=\"nvolveqa_40k\")\n", - " \n", + " embeddings = NVIDIAEmbeddings(model=\"ai-embed-qa-4\")\n", + "\n", " for document in documents:\n", " texts = splitter.split_text(document.page_content)\n", "\n", @@ -336,7 +254,7 @@ "source": [ "### Second stage is to load the embeddings from the vector store and build a RAG using NVIDIAEmbeddings\n", "\n", - "Create the embeddings model using NVIDIA Retrieval QA Embedding endpoint. This model represents words, phrases, or other entities as vectors of numbers and understands the relation between words and phrases. See here for reference: https://catalog.ngc.nvidia.com/orgs/nvidia/teams/ai-foundation/models/nvolve-40k" + "Create the embeddings model using NVIDIA Retrieval QA Embedding endpoint. This model represents words, phrases, or other entities as vectors of numbers and understands the relation between words and phrases. See here for reference: https://build.nvidia.com/nvidia/embed-qa-4" ] }, { @@ -358,7 +276,7 @@ "\n", "create_embeddings()\n", "\n", - "embedding_model = NVIDIAEmbeddings(model=\"nvolveqa_40k\")\n" + "embedding_model = NVIDIAEmbeddings(model=\"ai-embed-qa-4\")\n" ] }, { @@ -386,7 +304,7 @@ "id": "01153bc4", "metadata": {}, "source": [ - "Create a ConversationalRetrievalChain chain using NeMoLLM. In this chain we demonstrate the use of 2 LLMs: one for summarization and another for chat. This improves the overall result in more complicated scenarios. We'll use Llama2 70B for the first LLM and Mixtral for the Chat element in the chain. We add a question_generator to generate relevant query prompt. See here for reference: https://python.langchain.com/docs/modules/chains/popular/chat_vector_db#conversationalretrievalchain-with-streaming-to-stdout" + "Create a ConversationalRetrievalChain chain using NeMoLLM. In this chain we demonstrate the use of 2 LLMs: one for summarization and another for chat. This improves the overall result in more complicated scenarios. We'll use Llama3 70B for the first LLM and Mixtral for the Chat element in the chain. We add a question_generator to generate relevant query prompt. See here for reference: https://python.langchain.com/docs/modules/chains/popular/chat_vector_db#conversationalretrievalchain-with-streaming-to-stdout" ] }, { @@ -396,13 +314,13 @@ "metadata": {}, "outputs": [], "source": [ - "llm = ChatNVIDIA(model=\"llama2_70b\")\n", + "llm = ChatNVIDIA(model=\"meta/llama3-70b-instruct\")\n", "\n", "memory = ConversationBufferMemory(memory_key=\"chat_history\", return_messages=True)\n", "\n", "question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)\n", "\n", - "chat = ChatNVIDIA(model=\"mixtral_8x7b\", temperature=0.1, max_tokens=1000, top_p=1.0)\n", + "chat = ChatNVIDIA(model=\"ai-mixtral-8x7b-instruct\", temperature=0.1, max_tokens=1000, top_p=1.0)\n", "\n", "doc_chain = load_qa_chain(chat , chain_type=\"stuff\", prompt=QA_PROMPT)\n", "\n", @@ -489,7 +407,7 @@ "metadata": {}, "outputs": [], "source": [ - "llm = ChatNVIDIA(model=\"llama2_70b\", temperature=0.1, max_tokens=1000, top_p=1.0)\n", + "llm = ChatNVIDIA(model=\"meta/llama3-70b-instruct\", temperature=0.1, max_tokens=1000, top_p=1.0)\n", "\n", "qa_prompt=QA_PROMPT\n", "\n", diff --git a/notebooks/11_LangGraph_HandlingAgent_IntermediateSteps.ipynb b/notebooks/06_LangGraph_HandlingAgent_IntermediateSteps.ipynb similarity index 98% rename from notebooks/11_LangGraph_HandlingAgent_IntermediateSteps.ipynb rename to notebooks/06_LangGraph_HandlingAgent_IntermediateSteps.ipynb index 42d6eb703..8a85c7712 100644 --- a/notebooks/11_LangGraph_HandlingAgent_IntermediateSteps.ipynb +++ b/notebooks/06_LangGraph_HandlingAgent_IntermediateSteps.ipynb @@ -50,9 +50,12 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install wikipedia\n", - "!pip install langgraph\n", - "!pip install faiss-gpu" + "!pip install --upgrade pip\n", + "!pip install wikipedia==1.4.0\n", + "!pip install langchain-community==0.2.2\n", + "!pip install langchain==0.2.2\n", + "!pip install langgraph==0.0.62\n", + "!pip install faiss-gpu==1.7.2" ] }, { @@ -115,8 +118,8 @@ "from langchain_nvidia_ai_endpoints import ChatNVIDIA\n", "from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings\n", "\n", - "llm = ChatNVIDIA(model=\"ai-mixtral-8x7b-instruct\", nvidia_api_key=nvapi_key, max_tokens=2048)\n", - "embedder = NVIDIAEmbeddings(model=\"ai-embed-qa-4\")\n" + "llm = ChatNVIDIA(model=\"mistralai/mixtral-8x7b-instruct-v0.1\", nvidia_api_key=nvapi_key, max_tokens=2048)\n", + "embedder = NVIDIAEmbeddings(model=\"NV-Embed-QA\")\n" ] }, { @@ -185,7 +188,7 @@ "outputs": [], "source": [ "## If you previously preprocessed and saved the vector store to disk, then reload it here\n", - "faissDB = FAISS.load_local(\"/workspace/save_embedding/sv\", embedder)\n", + "faissDB = FAISS.load_local(\"/workspace/save_embedding/sv\", embedder, allow_dangerous_deserialization=True)\n", "retriever = faissDB.as_retriever()" ] }, diff --git a/notebooks/12_Chat_wtih_nvidia_financial_reports.ipynb b/notebooks/07_Chat_with_nvidia_financial_reports.ipynb similarity index 94% rename from notebooks/12_Chat_wtih_nvidia_financial_reports.ipynb rename to notebooks/07_Chat_with_nvidia_financial_reports.ipynb index 634bc10d8..9ad5c16a7 100644 --- a/notebooks/12_Chat_wtih_nvidia_financial_reports.ipynb +++ b/notebooks/07_Chat_with_nvidia_financial_reports.ipynb @@ -5,9 +5,9 @@ "id": "4ff7339a", "metadata": {}, "source": [ - "# Notebook: Chating with NVIDIA Financial Reports\n", + "# Notebook: Chatting with NVIDIA Financial Reports\n", "\n", - " In this notebook, we are going to use milvus as vectorstore, the **mixtral_8x7b as LLM** and **nvolveqa_40k embedding** provided by [NVIDIA_AI_Endpoint](https://python.langchain.com/docs/integrations/text_embedding/nvidia_ai_endpoints) as LLM and embedding model, and build a simply RAG example for chatting with NVIDIA Financial Reports.\n", + " In this notebook, we are going to use milvus as vectorstore, the **mixtral_8x7b as LLM** and **ai-embed-qa-4 embedding** provided by [NVIDIA_AI_Endpoint](https://python.langchain.com/docs/integrations/text_embedding/nvidia_ai_endpoints) as LLM and embedding model, and build a simply RAG example for chatting with NVIDIA Financial Reports.\n", "\n", "\n", "NVIDIA financial reports are available pubicly in nvidianews. \n", @@ -61,7 +61,7 @@ "metadata": {}, "outputs": [], "source": [ - "# test run and see that you can genreate a respond successfully \n", + "# test run and see that you can genreate a respond successfully\n", "from langchain_nvidia_ai_endpoints import ChatNVIDIA,NVIDIAEmbeddings\n", "llm = ChatNVIDIA(model=\"ai-mixtral-8x7b-instruct\", nvidia_api_key=nvapi_key, max_tokens=1024)\n", "from langchain.vectorstores import Milvus\n", @@ -102,13 +102,13 @@ "url_template2 = \"https://nvidianews.nvidia.com/news/nvidia-announces-financial-results-for-{quarter}-quarter-and-fiscal-{year}\"\n", "\n", "for quarter in [\"first\", \"second\", \"third\", \"fourth\"]:\n", - " for year in range(2020,2025): \n", + " for year in range(2020,2025):\n", " args = {\"quarter\":quarter, \"year\": str(year)}\n", " if quarter == \"fourth\":\n", " urls_content.append(requests.get(url_template2.format(**args)).content)\n", " else:\n", " urls_content.append(requests.get(url_template1.format(**args)).content)\n", - " \n" + "\n" ] }, { @@ -143,7 +143,7 @@ " url = og_url_meta.get(\"content\", \"\")\n", "\n", " for table in soup.find_all(\"table\"):\n", - " tables.append(markdownify.markdownify(str(table))) \n", + " tables.append(markdownify.markdownify(str(table)))\n", " table.decompose()\n", "\n", " text_content = soup.get_text(separator=' ', strip=True)\n", @@ -153,15 +153,14 @@ " except:\n", " print(\"parse error\")\n", " return \"\", \"\", \"\", \"\", []\n", - " \n", + "\n", "parsed_htmls = []\n", "for url_content in urls_content:\n", " soup = BeautifulSoup(url_content, 'html.parser')\n", " url, title, content, tables = extract_url_title_time(soup)\n", " parsed_htmls.append({\"url\":url, \"title\":title, \"content\":content, \"tables\":tables})\n", "\n", - "\n", - " " + "\n" ] }, { @@ -179,7 +178,7 @@ "metadata": {}, "outputs": [], "source": [ - "# summarize tables \n", + "# summarize tables\n", "def get_table_summary(table, title, llm):\n", " res = \"\"\n", " try:\n", @@ -189,7 +188,7 @@ " TABLE is from \"{title}\". Summarize the information in TABLE into SUMMARY. SUMMARY MUST be concise. Return SUMMARY only and nothing else.\n", " TABLE: ```{table}```\n", " Summary:\n", - " [/INST] \n", + " [/INST]\n", " \"\"\"\n", " result = llm.invoke(prompt)\n", " res = result.content\n", @@ -207,8 +206,7 @@ " for idx, table in enumerate(parsed_item['tables']):\n", " print(f\"parsing tables in {title}...\")\n", " table = get_table_summary(table, title, llm)\n", - " parsed_item['tables'][idx] = table\n", - " " + " parsed_item['tables'][idx] = table\n" ] }, { @@ -245,11 +243,11 @@ " url = parsed_item['url']\n", " text_content = parsed_item['content']\n", " documents.append(Document(page_content=text_content, metadata = {'title':title, 'url':url}))\n", - " \n", + "\n", " for idx, table in enumerate(parsed_item['tables']):\n", " table_content = table\n", " documents.append(Document(page_content=table, metadata = {'title':title, 'url':url}))\n", - " \n", + "\n", "documents = text_splitter.split_documents(documents)\n", "print(f\"obtain {len(documents)} chunks\")" ] @@ -267,7 +265,7 @@ " embedding_function=embedder_document,\n", " collection_name=COLLECTION_NAME,\n", " connection_args={\n", - " \"host\": \"milvus\", \n", + " \"host\": \"milvus\",\n", " \"port\": \"19530\"},\n", " drop_old = True,\n", " auto_id = True\n", @@ -315,9 +313,9 @@ " * You MUST follow the below format as an example for this citation section:\n", " Here are the sources used to generate this response:\n", " * [Title](URL)\n", - "[/INST] \n", + "[/INST]\n", "[INST]\n", - "QUESTION: {question} \n", + "QUESTION: {question}\n", "FINAL ANSWER:[/INST]\"\"\"\n", "\n", "prompt_template = PromptTemplate(template=PROMPT_TEMPLATE, input_variables=[\"context\", \"question\"])\n", @@ -329,17 +327,17 @@ " for chunk in chunks:\n", " context = context + \"\\n Content: \" + chunk.page_content + \" | Title: (\" + chunk.metadata[\"title\"] + \") | URL: (\" + chunk.metadata.get(\"url\", \"source\") + \")\"\n", " return context\n", - " \n", + "\n", "\n", "def generate_answer(llm, vectorstore, prompt_template, question):\n", - " retrieved_chunks = vectorstore.similarity_search(question) \n", + " retrieved_chunks = vectorstore.similarity_search(question)\n", " context = build_context(retrieved_chunks)\n", " args = {\"context\":context, \"question\":question}\n", " prompt = prompt_template.format(**args)\n", " ans = llm.invoke(prompt)\n", " return ans.content\n", - " \n", - " \n", + "\n", + "\n", "question = \"what are 2024 Q1 revenues?\"\n", "\n", "generate_answer(llm, vectorstore, prompt_template, question)" diff --git a/notebooks/08_RAG_Langchain_with_Local_NIM.ipynb b/notebooks/08_RAG_Langchain_with_Local_NIM.ipynb new file mode 100644 index 000000000..7f8123367 --- /dev/null +++ b/notebooks/08_RAG_Langchain_with_Local_NIM.ipynb @@ -0,0 +1,502 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "184878ec-80c1-4533-a7f8-f7fecbc3d8ad", + "metadata": {}, + "source": [ + "# Build a RAG using a locally hosted NIM\n", + "\n", + "In this notebook we demonstrate how to build a RAG using [NVIDIA Inference Microservices (NIM)](https://build.nvidia.com/explore/discover). We locally host a Llama3-8b-instruct NIM and deploy it using [ NVIDIA AI Endpoints for LangChain](https://python.langchain.com/docs/integrations/chat/nvidia_ai_endpoints/).\n", + "\n", + "We then create a vector store by downloading web pages and generating their embeddings using FAISS. We then showcase two different chat chains for querying the vector store. For this example, we use the NVIDIA Triton documentation website, though the code can be easily modified to use any other source. \n", + "\n", + "### First stage is to load NVIDIA Triton documentation from the web, chunkify the data, and generate embeddings using FAISS\n", + "\n", + "To get started:\n", + "\n", + "1. Generate a NGC API [here](https://org.ngc.nvidia.com/setup/personal-keys)\n", + "\n", + "2. Export the API key (export NGC_API_KEY=) This key will need to be passed to docker run in the next section as the NGC_API_KEY environment variable to download the appropriate models and resources when starting the NIM.\n", + "\n", + "3. Download and install the NGC CLI following the [NGC Setup steps](https://docs.ngc.nvidia.com/cli/index.html?_gl=1*22f68y*_gcl_au*MTE2NTMwMTA2NC4xNzE1NzY4NzE4). Follow the steps on that page to set the NGC CLI and docker client configs appropriately.\n", + "\n", + "4. To pull the NIM container image from NGC, first authenticate with the NVIDIA Container Registry with the following command\n", + "\n", + "(Note: In order to run this notebook in a virtual environment, you need to launch the NIM Docker container in the background outside of the notebook environment prior to running the LangChain code in the notebook cells. Create a virtual environment and install the dependencies present inside the notebooks/requirements.txt file by pip install -r notebooks/requirements.txt. Run the commands in the first 3 cells from a terminal then begin with the 4th cell (curl inference command) within the notebook environment.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1308d67c", + "metadata": {}, + "outputs": [], + "source": [ + "!echo \"$NGC_API_KEY\" | docker login nvcr.io --username '$oauthtoken' --password-stdin" + ] + }, + { + "cell_type": "markdown", + "id": "9c2403b8", + "metadata": {}, + "source": [ + "Set up location for caching the model artifacts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06a23a6d", + "metadata": {}, + "outputs": [], + "source": [ + "!export LOCAL_NIM_CACHE=~/.cache/nim\n", + "!mkdir -p \"$LOCAL_NIM_CACHE\"\n", + "!chmod 777 \"$LOCAL_NIM_CACHE\"" + ] + }, + { + "cell_type": "markdown", + "id": "19a7e489", + "metadata": {}, + "source": [ + "Launch the NIM microservice" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f612dd", + "metadata": {}, + "outputs": [], + "source": [ + "!docker run -d --name meta-llama3-8b-instruct --gpus all -e NGC_API_KEY -v \"$LOCAL_NIM_CACHE:/opt/nim/.cache\" -u $(id -u) -p 8000:8000 nvcr.io/nim/meta/llama3-8b-instruct:1.0.0" + ] + }, + { + "cell_type": "markdown", + "id": "37e2fcda", + "metadata": {}, + "source": [ + "Before we continue and connect the NIM to LangChain, let's test it using a simple OpenAI completion request" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af3bf04b", + "metadata": {}, + "outputs": [], + "source": [ + "!curl -X 'POST' \\\n", + " \"http://0.0.0.0:8000/v1/completions\" \\\n", + " -H \"accept: application/json\" \\\n", + " -H \"Content-Type: application/json\" \\\n", + " -d '{\"model\": \"meta/llama3-8b-instruct\", \"prompt\": \"Once upon a time\", \"max_tokens\": 64}'" + ] + }, + { + "cell_type": "markdown", + "id": "79c2aa6f", + "metadata": {}, + "source": [ + "Now setup the LangChain flow by installing prerequisite libraries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5966ea5a", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install langchain\n", + "!pip install langchain_nvidia_ai_endpoints\n", + "!pip install faiss-cpu" + ] + }, + { + "cell_type": "markdown", + "id": "74b0c989", + "metadata": {}, + "source": [ + "Set up API key, which you can get from the [API Catalog](https://build.nvidia.com/)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79771ce9", + "metadata": {}, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "if not os.environ.get(\"NVIDIA_API_KEY\", \"\").startswith(\"nvapi-\"):\n", + " nvapi_key = getpass.getpass(\"Enter your NVIDIA API key: \")\n", + " assert nvapi_key.startswith(\"nvapi-\"), f\"{nvapi_key[:5]}... is not a valid key\"\n", + " os.environ[\"NVIDIA_API_KEY\"] = nvapi_key" + ] + }, + { + "cell_type": "markdown", + "id": "5584e3b1", + "metadata": {}, + "source": [ + "We can now deploy the NIM in LangChain by specifying the base URL" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35baa8c6", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_nvidia_ai_endpoints import ChatNVIDIA\n", + "\n", + "llm = ChatNVIDIA(base_url=\"http://0.0.0.0:8000/v1\", model=\"meta/llama3-8b-instruct\", temperature=0.1, max_tokens=1000, top_p=1.0)\n", + "\n", + "result = llm.invoke(\"What is the capital of France?\")\n", + "print(result.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42bf2619-1ca3-4477-82b8-88c240dd87ad", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from langchain.chains import ConversationalRetrievalChain, LLMChain\n", + "from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT, QA_PROMPT\n", + "from langchain.chains.question_answering import load_qa_chain\n", + "from langchain.memory import ConversationBufferMemory\n", + "from langchain.vectorstores import FAISS\n", + "from langchain.text_splitter import RecursiveCharacterTextSplitter\n", + "from langchain_nvidia_ai_endpoints import ChatNVIDIA\n", + "from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "eb7f8822", + "metadata": {}, + "source": [ + "Helper functions for loading html files, which we'll use to generate the embeddings. We'll use this later to load the relevant html documents from the Triton documentation website and convert to a vector store." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8097819", + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "from typing import List, Union\n", + "\n", + "import requests\n", + "from bs4 import BeautifulSoup\n", + "\n", + "def html_document_loader(url: Union[str, bytes]) -> str:\n", + " \"\"\"\n", + " Loads the HTML content of a document from a given URL and return it's content.\n", + "\n", + " Args:\n", + " url: The URL of the document.\n", + "\n", + " Returns:\n", + " The content of the document.\n", + "\n", + " Raises:\n", + " Exception: If there is an error while making the HTTP request.\n", + "\n", + " \"\"\"\n", + " try:\n", + " response = requests.get(url)\n", + " html_content = response.text\n", + " except Exception as e:\n", + " print(f\"Failed to load {url} due to exception {e}\")\n", + " return \"\"\n", + "\n", + " try:\n", + " # Create a Beautiful Soup object to parse html\n", + " soup = BeautifulSoup(html_content, \"html.parser\")\n", + "\n", + " # Remove script and style tags\n", + " for script in soup([\"script\", \"style\"]):\n", + " script.extract()\n", + "\n", + " # Get the plain text from the HTML document\n", + " text = soup.get_text()\n", + "\n", + " # Remove excess whitespace and newlines\n", + " text = re.sub(\"\\s+\", \" \", text).strip()\n", + "\n", + " return text\n", + " except Exception as e:\n", + " print(f\"Exception {e} while loading document\")\n", + " return \"\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b6a2d1e0", + "metadata": {}, + "source": [ + "Read html files and split text in preparation for embedding generation\n", + "Note chunk_size value must match the specific LLM used for embedding genetation\n", + "\n", + "Make sure to pay attention to the chunk_size parameter in TextSplitter. Setting the right chunk size is critical for RAG performance, as much of a RAG’s success is based on the retrieval step finding the right context for generation. The entire prompt (retrieved chunks + user query) must fit within the LLM’s context window. Therefore, you should not specify chunk sizes too big, and balance them out with the estimated query size. For example, while OpenAI LLMs have a context window of 8k-32k tokens, Llama3 is limited to 8k tokens. Experiment with different chunk sizes, but typical values should be 100-600, depending on the LLM." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56aa8900", + "metadata": {}, + "outputs": [], + "source": [ + "def create_embeddings(embedding_path: str = \"./embed\"):\n", + "\n", + " embedding_path = \"./embed\"\n", + " print(f\"Storing embeddings to {embedding_path}\")\n", + "\n", + " # List of web pages containing NVIDIA Triton technical documentation\n", + " urls = [\n", + " \"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/index.html\",\n", + " \"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/getting_started/quickstart.html\",\n", + " \"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/model_repository.html\",\n", + " \"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/model_analyzer.html\",\n", + " \"https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/user_guide/architecture.html\",\n", + " ]\n", + "\n", + " documents = []\n", + " for url in urls:\n", + " document = html_document_loader(url)\n", + " documents.append(document)\n", + "\n", + "\n", + " text_splitter = RecursiveCharacterTextSplitter(\n", + " chunk_size=1000,\n", + " chunk_overlap=0,\n", + " length_function=len,\n", + " )\n", + " texts = text_splitter.create_documents(documents)\n", + " index_docs(url, text_splitter, texts, embedding_path)\n", + " print(\"Generated embedding successfully\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "4d4e2097", + "metadata": {}, + "source": [ + "Generate embeddings using NVIDIA Retrieval QA Embedding NIM and NVIDIA AI Endpoints for LangChain and save embeddings to offline vector store in the /embed directory for future re-use" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc7e6a93", + "metadata": {}, + "outputs": [], + "source": [ + "def index_docs(url: Union[str, bytes], splitter, documents: List[str], dest_embed_dir) -> None:\n", + " \"\"\"\n", + " Split the document into chunks and create embeddings for the document\n", + "\n", + " Args:\n", + " url: Source url for the document.\n", + " splitter: Splitter used to split the document\n", + " documents: list of documents whose embeddings needs to be created\n", + " dest_embed_dir: destination directory for embeddings\n", + "\n", + " Returns:\n", + " None\n", + " \"\"\"\n", + " embeddings = NVIDIAEmbeddings(model=\"ai-embed-qa-4\", truncate=\"END\")\n", + "\n", + " for document in documents:\n", + " texts = splitter.split_text(document.page_content)\n", + "\n", + " # metadata to attach to document\n", + " metadatas = [document.metadata]\n", + "\n", + " # create embeddings and add to vector store\n", + " if os.path.exists(dest_embed_dir):\n", + " update = FAISS.load_local(folder_path=dest_embed_dir, embeddings=embeddings)\n", + " update.add_texts(texts, metadatas=metadatas)\n", + " update.save_local(folder_path=dest_embed_dir)\n", + " else:\n", + " docsearch = FAISS.from_texts(texts, embedding=embeddings, metadatas=metadatas)\n", + " docsearch.save_local(folder_path=dest_embed_dir)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "44650d71", + "metadata": {}, + "source": [ + "### Second stage is to load the embeddings from the vector store and build a RAG using NVIDIAEmbeddings\n", + "\n", + "Create the embeddings model using NVIDIA Retrieval QA Embedding NIM from the API Catalog. This model represents words, phrases, or other entities as vectors of numbers and understands the relation between words and phrases. See here for reference: https://build.nvidia.com/nvidia/embed-qa-4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10db1c5c-f515-460f-bf23-5d68f195e52b", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "create_embeddings()\n", + "\n", + "embedding_model = NVIDIAEmbeddings(model=\"ai-embed-qa-4\", truncate=\"END\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "73f9f5e2", + "metadata": {}, + "source": [ + "Load documents from vector database using FAISS" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d55bb79e-5bb6-409d-8ead-3c3006aeb2ed", + "metadata": {}, + "outputs": [], + "source": [ + "# Embed documents\n", + "embedding_path = \"embed/\"\n", + "docsearch = FAISS.load_local(folder_path=embedding_path, embeddings=embedding_model)" + ] + }, + { + "cell_type": "markdown", + "id": "7614e948-aab6-40d5-bf14-4f8ba99b1329", + "metadata": {}, + "source": [ + "Create a ConversationalRetrievalChain chain using a local NIM. We'll use the Llama3 8B NIM we created and deployed locally, add memory for chat history, and connect to the vector store via the embedding model. See here for reference: https://python.langchain.com/docs/modules/chains/popular/chat_vector_db#conversationalretrievalchain-with-streaming-to-stdout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94b49b4a", + "metadata": {}, + "outputs": [], + "source": [ + "llm = ChatNVIDIA(base_url=\"http://0.0.0.0:8000/v1\", model=\"meta/llama3-8b-instruct\", temperature=0.1, max_tokens=1000, top_p=1.0)\n", + "\n", + "memory = ConversationBufferMemory(memory_key=\"chat_history\", return_messages=True)\n", + "\n", + "qa_prompt=QA_PROMPT\n", + "\n", + "doc_chain = load_qa_chain(llm, chain_type=\"stuff\", prompt=QA_PROMPT)\n", + "\n", + "qa = ConversationalRetrievalChain.from_llm(\n", + " llm=llm,\n", + " retriever=docsearch.as_retriever(),\n", + " chain_type=\"stuff\",\n", + " memory=memory,\n", + " combine_docs_chain_kwargs={'prompt': qa_prompt},\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f60f2240", + "metadata": {}, + "source": [ + "Now try asking a question about Triton with the simpler chain. Compare the answer to the result with previous complex chain model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9add6e2e", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"What is Triton?\"\n", + "result = qa({\"question\": query})\n", + "print(result.get(\"answer\"))" + ] + }, + { + "cell_type": "markdown", + "id": "43b1cddd", + "metadata": {}, + "source": [ + "Ask another question about Triton" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62654a9a", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"Does Triton support ONNX?\"\n", + "result = qa({\"question\": query})\n", + "print(result.get(\"answer\"))" + ] + }, + { + "cell_type": "markdown", + "id": "f178ac86", + "metadata": {}, + "source": [ + "Finally showcase chat capabilites by asking a question about the previous query" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "781e058e", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"But why?\"\n", + "result = qa({\"question\": query})\n", + "print(result.get(\"answer\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/Dockerfile.gpu_notebook b/notebooks/Dockerfile.gpu_notebook index 6eb23b2f2..baefa4c0a 100644 --- a/notebooks/Dockerfile.gpu_notebook +++ b/notebooks/Dockerfile.gpu_notebook @@ -1,5 +1,5 @@ # Use a base image with Python -FROM nvcr.io/nvidia/pytorch:23.05-py3 +FROM nvcr.io/nvidia/pytorch:23.05-py3 # Set working directory WORKDIR /app @@ -14,10 +14,6 @@ COPY ./notebooks/toy_data/* notebooks/toy_data/ COPY ./notebooks/imgs/* notebooks/imgs/ -COPY ./integrations/langchain/llms/triton_trt_llm.py . - -COPY ./integrations/langchain/llms/nv_aiplay.py . - COPY ./notebooks/requirements.txt . # Run pip dependencies diff --git a/notebooks/Dockerfile.notebooks b/notebooks/Dockerfile.notebooks index b2cc0a1e1..95e5715a4 100644 --- a/notebooks/Dockerfile.notebooks +++ b/notebooks/Dockerfile.notebooks @@ -13,10 +13,6 @@ COPY ./notebooks/dataset.zip . COPY ./notebooks/imgs/* imgs/ -COPY ./integrations/langchain/llms/triton_trt_llm.py . - -COPY ./integrations/langchain/llms/nv_aiplay.py . - COPY ./notebooks/requirements.txt . # Run pip dependencies diff --git a/notebooks/requirements.txt b/notebooks/requirements.txt index ffe4af81c..c80024650 100644 --- a/notebooks/requirements.txt +++ b/notebooks/requirements.txt @@ -10,9 +10,8 @@ opencv-python==4.8.0.74 llama-hub==0.0.43 pymilvus==2.3.1 jupyterlab==4.0.8 -langchain-nvidia-trt==0.0.1rc0 langchain-core==0.1.29 -langchain-nvidia-ai-endpoints==0.0.11 +langchain-nvidia-ai-endpoints==0.1.1 atlassian-python-api==3.41.4 gradio==3.48.0 markdownify==0.12.1 diff --git a/tools/evaluation/01_synthetic_data_generation.ipynb b/tools/evaluation/01_synthetic_data_generation.ipynb index 262e8e79f..05af3be96 100644 --- a/tools/evaluation/01_synthetic_data_generation.ipynb +++ b/tools/evaluation/01_synthetic_data_generation.ipynb @@ -209,7 +209,7 @@ "\n", "**NVIDIA AI Playground** on NGC allows developers to experience state of the art LLMs accelerated on NVIDIA DGX Cloud with NVIDIA TensorRT nd Triton Inference Server. Developers get **free credits for 10K requests** to any of the available models. Sign up process is easy. follow the steps here. \n", "\n", - "We are going to use theAI playground'ss `llama2-70B `LLM to generate the Question-Answer pairs." + "We are going to use the [Nvidia API catalog](https://build.nvidia.com/meta/llama3-70b) `llama3-70B `LLM to generate the Question-Answer pairs." ] }, { @@ -242,7 +242,7 @@ "os.environ['NVIDIA_API_KEY'] = \"nvapi-*\"\n", "\n", "llm = ChatNVIDIA(\n", - " model=\"llama2_70b\",\n", + " model=\"meta/llama3-70b-instruct\",\n", " temperature=0.2,\n", " max_tokens=300\n", ")" diff --git a/tools/evaluation/02_filling_RAG_outputs_for_Evaluation.ipynb b/tools/evaluation/02_filling_RAG_outputs_for_Evaluation.ipynb index 50a1248d0..11110ae63 100644 --- a/tools/evaluation/02_filling_RAG_outputs_for_Evaluation.ipynb +++ b/tools/evaluation/02_filling_RAG_outputs_for_Evaluation.ipynb @@ -7,15 +7,15 @@ "source": [ "## Notebook 2: Filling RAG outputs For Evaluation\n", "\n", - "In this notebook, we will use the example RAG pipeline to populate the RAG outputs: contexts (retrieved relevant documents) and answer (generated by RAG pipeline).\n", + "In this notebook, we will use the deployed RAG pipeline to populate the RAG outputs: contexts (retrieved relevant documents) and answer (generated by RAG pipeline).\n", "\n", - "The example RAG pipeline provided as part of this repository uses [LlamaIndex](https://gpt-index.readthedocs.io/en/stable/) to build a chatbot that references a custom knowledge base. \n", + "The RAG pipeline used as part of this repository needs to be deployed before using steps in [Build and Start API Catalog Containers](https://nvidia.github.io/GenerativeAIExamples/latest/api-catalog.html#build-and-start-the-containers) to expose required API calls from chain-server. \n", "\n", - "If you want to learn more about how the example RAG works, please see [03_llama_index_simple.ipynb](../notebooks/03_llama_index_simple.ipynb).\n", + "If you want to learn more about how the deployed pipelione works in the backend, please see [03_llama_index_simple.ipynb](../notebooks/03_llama_index_simple.ipynb).\n", "\n", - "- **Steps 1-5**: Build the RAG pipeline.\n", - "- **Step 6**: Build the Query Engine, exposing the Retriever and Generator outputs\n", - "- **Step 7**: Fill the RAG outputs " + "- **Steps 1**: Setting up the dataset directory and Defining API endpoints \n", + "- **Step 2**: Ingest Documents\n", + "- **Step 3**: Fill the RAG outputs " ] }, { @@ -23,24 +23,7 @@ "id": "191e7b90-128e-4432-82ab-897426389d06", "metadata": {}, "source": [ - "### Steps 1-5: Build the RAG pipeline\n", - "\n", - "#### Define the LLM\n", - "Here we are using a local llm on triton and the address and gRPC port that the Triton is available on. \n", - "\n", - "***If you are using AI Playground (no local GPU) replace, the code in the cell two cells below with the following: ***\n", - "\n", - "```\n", - "import os\n", - "from nv_aiplay import GeneralLLM\n", - "os.environ['NVAPI_KEY'] = \"REPLACE_WITH_YOUR_API_KEY\"\n", - "\n", - "llm = GeneralLLM(\n", - " model=\"llama2_70b\",\n", - " temperature=0.2,\n", - " max_tokens=300\n", - ")\n", - "```" + "### Steps 1: Set up Dataset directory and define API endpoints" ] }, { @@ -61,167 +44,10 @@ "metadata": {}, "outputs": [], "source": [ - "from triton_trt_llm import TensorRTLLM\n", - "from llama_index.llms.langchain import LangChainLLM\n", - "trtllm =TensorRTLLM(server_url=\"llm:8001\", model_name=\"ensemble\", tokens=300)\n", - "llm = LangChainLLM(llm=trtllm)" - ] - }, - { - "cell_type": "markdown", - "id": "bc57b68d-afd5-4a0c-832c-0ad8f3f475d5", - "metadata": {}, - "source": [ - "#### Create a Prompt Template\n", - "\n", - "A [**prompt template**](https://gpt-index.readthedocs.io/en/latest/core_modules/model_modules/prompts.html) is a common paradigm in LLM development.\n", - "\n", - "They are a pre-defined set of instructions provided to the LLM and guide the output produced by the model. They can contain few shot examples and guidance and are a quick way to engineer the responses from the LLM. Llama 2 accepts the [prompt format](https://huggingface.co/blog/llama2#how-to-prompt-llama-2) shown in `LLAMA_PROMPT_TEMPLATE`, which we manipulate to be constructed with:\n", - "- The system prompt\n", - "- The context\n", - "- The user's question\n", - " \n", - "Much like LangChain's abstraction of prompts, LlamaIndex has similar abstractions for you to create prompts." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "682ec812-33be-430f-8bb1-ae3d68690198", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from llama_index.core import Prompt\n", - "\n", - "LLAMA_PROMPT_TEMPLATE = (\n", - " \"[INST] <>\"\n", - " \"Use the following context to answer the user's question. If you don't know the answer, just say that you don't know, don't try to make up an answer.\"\n", - " \"<>\"\n", - " \"[INST] Context: {context_str} Question: {query_str} Only return the helpful answer below and nothing else. Helpful answer:[/INST]\"\n", - ")\n", - "\n", - "qa_template = Prompt(LLAMA_PROMPT_TEMPLATE)" - ] - }, - { - "cell_type": "markdown", - "id": "d0af7922", - "metadata": {}, - "source": [ - "### Load Documents\n", - "Follow the step number 1 [defined here](../notebooks/05_dataloader.ipynb) to upload the pdf's to Milvus server.\n" - ] - }, - { - "cell_type": "markdown", - "id": "a7bb75ad", - "metadata": {}, - "source": [ - "In this rest of this section, we will load and split the pdfs of NVIDIA blogs. We will use the `SentenceTransformersTokenTextSplitter`.\n", - "Additionally, we use a LlamaIndex [``PromptHelper``](https://gpt-index.readthedocs.io/en/latest/api_reference/service_context/prompt_helper.html) to help deal with LLM context window token limitations. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fa366250-108e-45a0-88ce-e6f7274da8e1", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from langchain.text_splitter import SentenceTransformersTokenTextSplitter\n", - "from llama_index.core.node_parser import LangchainNodeParser\n", - "from llama_index.core import PromptHelper\n", - "\n", - "# setup the text splitter\n", - "TEXT_SPLITTER_MODEL = \"intfloat/e5-large-v2\"\n", - "TEXT_SPLITTER_TOKENS_PER_CHUNK = 510\n", - "TEXT_SPLITTER_CHUNCK_OVERLAP = 200\n", - "\n", - "text_splitter = SentenceTransformersTokenTextSplitter(\n", - " model_name=TEXT_SPLITTER_MODEL,\n", - " tokens_per_chunk=TEXT_SPLITTER_TOKENS_PER_CHUNK,\n", - " chunk_overlap=TEXT_SPLITTER_CHUNCK_OVERLAP,\n", - ")\n", - "\n", - "node_parser = LangchainNodeParser(text_splitter)\n", - "\n", - "\n", - "# Use the PromptHelper\n", - "\n", - "prompt_helper = PromptHelper(\n", - " context_window=4096,\n", - " num_output=256,\n", - " chunk_overlap_ratio=0.1,\n", - " chunk_size_limit=None\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "b8dab583-a12d-4fb1-a9eb-3a1b1f04075d", - "metadata": {}, - "source": [ - "#### Generate and Store Embeddings\n", - "##### a) Generate Embeddings \n", - "[Embeddings](https://python.langchain.com/docs/modules/data_connection/text_embedding/) for documents are created by vectorizing the document text; this vectorization captures the semantic meaning of the text. \n", - "\n", - "We will use [intfloat/e5-large-v2](https://huggingface.co/intfloat/e5-large-v2) for the embeddings." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e9011ba0-f3f6-41f0-8a15-48f264743545", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from langchain.embeddings import HuggingFaceEmbeddings\n", - "from llama_index.embeddings.langchain import LangchainEmbedding\n", - "\n", - "#Running the model on CPU as we want to conserve gpu memory.\n", - "#In the production deployment (API server shown as part of the 5th notebook we run the model on GPU)\n", - "model_name=\"intfloat/e5-large-v2\"\n", - "model_kwargs = {\"device\": \"cuda:0\"}\n", - "encode_kwargs = {\"normalize_embeddings\": False}\n", - "hf_embeddings = HuggingFaceEmbeddings(\n", - " model_name=model_name,\n", - " model_kwargs=model_kwargs,\n", - " encode_kwargs=encode_kwargs,\n", - ")\n", - "# Load in a specific embedding model\n", - "embed_model = LangchainEmbedding(hf_embeddings)" - ] - }, - { - "cell_type": "markdown", - "id": "8db99124-e438-406d-880d-557501a461d3", - "metadata": {}, - "source": [ - "##### b) Store Embeddings \n", - "\n", - "We will use the LlamaIndex module [`Settings`](https://docs.llamaindex.ai/en/stable/module_guides/supporting_modules/settings/?h=settings) to bundle commonly used resources during the indexing and querying stage.\n", - "\n", - "\n", - "In this example, we bundle the build resources: the LLM, the embedding model, the node parser, and the prompt helper. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e493f9d-589a-4820-902d-f68932bfb0d8", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from llama_index.core import Settings\n", - "\n", - "Settings.llm = llm\n", - "Settings.embed_model = embed_model\n", - "Settings.node_parser = node_parser\n", - "Settings.prompt_helper = prompt_helper" + "import os\n", + "url_upload = f\"http://chain-server:8081/documents\"\n", + "url_generate = f\"http://chain-server:8081/generate\"\n", + "url_doc_search = f\"http://chain-server:8081/search\"" ] }, { @@ -229,6 +55,7 @@ "id": "44e10c13", "metadata": {}, "source": [ + "### Steps 2: Ingest documents\n", "Ingest the dataset using the /documents endpoint in the chain-server." ] }, @@ -274,139 +101,16 @@ "import time\n", "\n", "start_time = time.time()\n", - "upload_pdf_files(\"dataset\", \"http://chain-server:8081/documents\")\n", + "upload_pdf_files(\"dataset\",url_upload )\n", "print(f\"--- {time.time() - start_time} seconds ---\")" ] }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "79c7923c-d778-4f32-be37-4314063ecd2f", - "metadata": {}, - "source": [ - "
\n", - " \n", - "⚠️ in the deployment of this workflow, [Milvus](https://milvus.io/) is running as a vector database microservice.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e94e53e-41a9-47d3-a9d3-7c0af4c07f76", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from llama_index.core import VectorStoreIndex\n", - "from llama_index.core.storage.storage_context import StorageContext\n", - "from llama_index.vector_stores.milvus import MilvusVectorStore\n", - "\n", - "# store\n", - "vector_store = MilvusVectorStore(uri=\"http://milvus:19530\",\n", - " dim=1024,\n", - " collection_name=\"developer_rag\",\n", - " index_config={\"index_type\": \"GPU_IVF_FLAT\", \"nlist\": 64},\n", - " search_config={\"nprobe\": 16},\n", - " overwrite=False\n", - ")\n", - "storage_context = StorageContext.from_defaults(vector_store=vector_store)\n", - "index = VectorStoreIndex.from_vector_store(vector_store)" - ] - }, - { - "cell_type": "markdown", - "id": "b3b58028-04fa-4050-9ec4-6526817fd9cf", - "metadata": {}, - "source": [ - "### Step 6: Build the Query Engine, exposing the Retriever and Generator outputs\n", - "\n", - "#### a) Limit the Retriever Total Output Length\n", - "\n", - "First, we need to restrict the output of the Retriever to a reasonable length so that the prompt can fit the context length of the LLM.\n", - "In this notebook, we will restrict it to 1000 (anything up to 1000 will ignored).\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6efc410c-f488-43aa-af65-c39376bd7ba5", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from llama_index.core.postprocessor.types import BaseNodePostprocessor\n", - "from typing import TYPE_CHECKING, List, Optional\n", - "from llama_index.core.utils import get_tokenizer\n", - "DEFAULT_MAX_CONTEXT = 1000\n", - "\n", - "# limit the Retriever total outputs length\n", - "class LimitRetrievedNodesLength(BaseNodePostprocessor):\n", - " \"\"\"Llama Index chain filter to limit token lengths.\"\"\"\n", - "\n", - " def _postprocess_nodes(\n", - " self, nodes: List[\"NodeWithScore\"], query_bundle: Optional[\"QueryBundle\"] = None\n", - " ) -> List[\"NodeWithScore\"]:\n", - " \"\"\"Filter function.\"\"\"\n", - " included_nodes = []\n", - " current_length = 0\n", - " limit = DEFAULT_MAX_CONTEXT\n", - "\n", - " tokenizer = get_tokenizer()\n", - " for node in nodes:\n", - " current_length += len(\n", - " tokenizer(\n", - " node.node.get_content(metadata_mode=MetadataMode.LLM)\n", - " )\n", - " )\n", - " if current_length > limit:\n", - " break\n", - " included_nodes.append(node)\n", - "\n", - " return included_nodes\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "e33cfed2-2a63-40be-8a7d-787ba04d2af9", - "metadata": {}, - "source": [ - "#### b) Build the Query Engine\n", - "\n", - "Now, let's build the query engine that takes a query and returns a response. Each vector index has a default corresponding query engine; for example, the default query engine for a vector index performs a standard top-k retrieval over the vector store.\n", - "We will use `RetrieverQueryEngine` to get the output of the Retriever and generator. Learn more about the RetrieverQueryEngine in the [documentation](https://gpt-index.readthedocs.io/en/latest/examples/query_engine/CustomRetrievers.html).\n", - "\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f56f37e0-341e-4d7d-b282-f374a16f55b2", - "metadata": {}, - "outputs": [], - "source": [ - "# import the relevant libraries\n", - "from llama_index.core.query_engine import RetrieverQueryEngine\n", - "from llama_index.core.schema import MetadataMode\n", - "\n", - "# Expose the retriever\n", - "retriever = index.as_retriever(similarity_top_k=2)\n", - "\n", - "query_engine = RetrieverQueryEngine.from_args(\n", - " retriever,\n", - " text_qa_template=qa_template,\n", - " node_postprocessors=[LimitRetrievedNodesLength()]\n", - ")" - ] - }, { "cell_type": "markdown", "id": "c6a58983-2069-450e-adf9-24b0f8736498", "metadata": {}, "source": [ - "### Step 7: Fill the RAG outputs \n", + "### Step 3: Fill the RAG outputs \n", "\n", "Let's now query the RAG pipeline and fill the outputs `contexts` and `answer` on the evaluation JSON file.\n", "\n", @@ -440,6 +144,20 @@ "Let now query the RAG pipeline and populate the `contexts` and `answer` fields." ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "339cbb2f", + "metadata": {}, + "outputs": [], + "source": [ + "import typing\n", + "\n", + "generate_api_params={\"use_knowledge_base\": True, \"temperature\":0.2,\"top_p\":0.7,\"max_tokens\": 256}\n", + "document_search_api_params={\"num_docs\": 1}\n", + "new_data=[]" + ] + }, { "cell_type": "code", "execution_count": null, @@ -450,16 +168,56 @@ "outputs": [], "source": [ "for entry in data:\n", - " limited_retrieval_length = LimitRetrievedNodesLength()\n", - " retrieved_text = \"\"\n", - " response = query_engine.query(entry[\"question\"])\n", - " entry[\"answer\"] = response.response\n", + " entry_generate = {\n", + " \"messages\":[\n", + " {\n", + " \"role\":\"user\",\n", + " \"content\":entry[\"question\"]\n", + " }\n", + " ],\n", + " \"use_knowledge_base\": generate_api_params[\"use_knowledge_base\"],\n", + " \"temperature\": generate_api_params[\"temperature\"],\n", + " \"top_p\": generate_api_params[\"top_p\"],\n", + " \"max_tokens\": generate_api_params[\"max_tokens\"],\n", + " \"stop\":[\n", + " \"string\"\n", + " ]\n", + " }\n", + " entry[\"answer\"] = \"\"\n", + " try:\n", + " with requests.post(url_generate, stream=True, json=entry_generate) as r:\n", + " for chunk in r.iter_lines():\n", + " raw_resp = chunk.decode(\"UTF-8\")\n", + " if not raw_resp:\n", + " continue\n", + " resp_dict = None\n", + " try:\n", + " print(raw_resp)\n", + " resp_dict = json.loads(raw_resp[6:])\n", + " resp_choices = resp_dict.get(\"choices\", [])\n", + " if len(resp_choices):\n", + " resp_str = resp_choices[0].get(\"message\", {}).get(\"content\", \"\")\n", + " entry[\"answer\"] += resp_str\n", + " except Exception as e:\n", + " print(f\"Exception Occured: {e}\")\n", + " except Exception as e:\n", + " print(f\"Exception Occured: {e}\")\n", + " entry[\"answer\"] = \"Answer couldn't be generated.\"\n", " print(entry[\"answer\"])\n", - " nodes = retriever.retrieve(entry[\"question\"])\n", - " included_nodes = limited_retrieval_length.postprocess_nodes(nodes)\n", - " for node in included_nodes:\n", - " retrieved_text = retrieved_text + \" \" + node.text\n", - " entry[\"contexts\"] = [retrieved_text]" + " entry_doc_search = {\n", + " \"query\": entry[\"question\"],\n", + " \"top_k\": document_search_api_params[\"num_docs\"]\n", + " }\n", + " response = requests.post(url_doc_search, json=entry_doc_search).json()\n", + " context_list =typing.cast(typing.List[typing.Dict[str, typing.Union[str, float]]], response)\n", + " contexts = [context.get(\"content\") for context in context_list['chunks']]\n", + " try:\n", + " entry[\"contexts\"] = [contexts[0]]\n", + " except Exception as e:\n", + " print(f\"Exception Occured: {e}\")\n", + " entry[\"contexts\"] = \"\"\n", + " new_data.append(entry)\n", + " print(len(entry[\"contexts\"]))" ] }, { diff --git a/tools/evaluation/03_eval_ragas.ipynb b/tools/evaluation/03_eval_ragas.ipynb index 64eaac22a..4025263cc 100644 --- a/tools/evaluation/03_eval_ragas.ipynb +++ b/tools/evaluation/03_eval_ragas.ipynb @@ -45,11 +45,11 @@ "source": [ "from langchain_nvidia_ai_endpoints import ChatNVIDIA, NVIDIAEmbeddings\n", "llm = ChatNVIDIA(\n", - " model=\"llama2_70b\",\n", + " model=\"meta/llama3-70b-instruct\",\n", " temperature=0.2,\n", " max_tokens=300,\n", ")\n", - "embeddings = NVIDIAEmbeddings(model=\"nvolveqa_40k\", model_type=\"passage\")" + "embeddings = NVIDIAEmbeddings(model=\"ai-embed-qa-4\", model_type=\"passage\")" ] }, { @@ -58,7 +58,7 @@ "metadata": {}, "source": [ "### Bring your own LLMs¶\n", - "Ragas uses langchain under the hood for connecting to LLMs for metrices that require them. This means you can swap out the default LLM (gpt-3.5) with llama2 70B from AI playground." + "Ragas uses langchain under the hood for connecting to LLMs for metrices that require them. This means you can swap out the default LLM (gpt-3.5) with llama3 70B from API catalog." ] }, { diff --git a/tools/evaluation/04_Human_Like_RAG_Evaluation-AIP.ipynb b/tools/evaluation/04_Human_Like_RAG_Evaluation-AIP.ipynb index df0c77b89..92894634b 100644 --- a/tools/evaluation/04_Human_Like_RAG_Evaluation-AIP.ipynb +++ b/tools/evaluation/04_Human_Like_RAG_Evaluation-AIP.ipynb @@ -13,7 +13,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We will use Llama2 70B model to evaluate the example RAG pipeline.\n", + "We will use Llama3 70B model to evaluate the example RAG pipeline.\n", "The score granulaity is from 1 to 5 where:\n", "\n", "- **Score 1**: Answer irrelevant or invalid, does not follow the context of the question or is irrelevant\n", @@ -78,7 +78,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Set your API key for Nvidia AI Playground" + "Get your [API key for Nvidia API Catalog for the meta/llama3-70b-instruct model](https://build.nvidia.com/explore/discover#llama3-70b) and populate it in the below cell." ] }, { @@ -89,9 +89,7 @@ "source": [ "import requests\n", "\n", - "invoke_url = \"https://api.nvcf.nvidia.com/v2/nvcf/pexec/functions/0e349b44-440a-44e1-93e9-abe8dcb27158\" #Llama 2 70B\n", - "fetch_url_format = \"https://api.nvcf.nvidia.com/v2/nvcf/pexec/status/\"\n", - "\n", + "invoke_url = \"https://integrate.api.nvidia.com/v1/chat/completions\" #Llama 3 70B Instruct\n", "# do not remove Bearer from Authorization, replace with api key\n", "headers = {\n", " \"Authorization\": \"Bearer \",\n", @@ -116,7 +114,7 @@ "We also ask the LLM to consider both the reference answer and context (ground truth) when evaluating the response provided by the RAG pipeline.\n", "Finally, we ask the LLM to provide a score on a scale of 1-5 (likert scale) and ask it to provide an explanation.\n", "\n", - "Here is an example of judge_template that we will use with Llama2 70B. Notice the evaluation examples provided in the prompt. This will help guide the LLM." + "Here is an example of judge_template that we will use with Llama3 70B. Notice the evaluation examples provided in the prompt. This will help guide the LLM." ] }, { @@ -206,6 +204,7 @@ " \"role\": \"user\"\n", " }\n", " ],\n", + " \"model\": \"meta/llama3-70b-instruct\",\n", " \"temperature\": 0.1,\n", " \"top_p\": 1.0,\n", " \"max_tokens\": 200,\n", diff --git a/tools/evaluation/Dockerfile.eval b/tools/evaluation/Dockerfile.eval index d0fc923a3..273102489 100644 --- a/tools/evaluation/Dockerfile.eval +++ b/tools/evaluation/Dockerfile.eval @@ -12,10 +12,6 @@ COPY ./notebooks/dataset.zip . COPY ./tools/evaluation/imgs/* imgs/ -COPY ./integrations/langchain/llms/triton_trt_llm.py . - -COPY ./integrations/langchain/llms/nv_aiplay.py . - COPY ./tools/evaluation/requirements.txt . COPY ./tools/evaluation/qa_generation.json . @@ -25,7 +21,7 @@ RUN pip3 install -r requirements.txt RUN apt-get update && apt-get install -y unzip wget git libgl1-mesa-glx libglib2.0-0 -# Expose port 8888 for JupyterLab +# Expose port 8889 for JupyterLab EXPOSE 8889 # Start JupyterLab when the container runs diff --git a/tools/evaluation/requirements.txt b/tools/evaluation/requirements.txt index f3e685d0b..657fe6f83 100644 --- a/tools/evaluation/requirements.txt +++ b/tools/evaluation/requirements.txt @@ -11,6 +11,5 @@ jupyterlab==4.0.8 ragas==0.1.7 seaborn==0.13.0 langchain-core==0.1.40 -langchain-nvidia-ai-endpoints==0.0.11 -langchain-nvidia-trt==0.0.1rc0 +langchain-nvidia-ai-endpoints==0.1.1 atlassian-python-api==3.41.4 diff --git a/tools/observability/llamaindex/opentelemetry_callback.py b/tools/observability/llamaindex/opentelemetry_callback.py index f024cd3ae..f76fe8c46 100644 --- a/tools/observability/llamaindex/opentelemetry_callback.py +++ b/tools/observability/llamaindex/opentelemetry_callback.py @@ -153,7 +153,10 @@ def on_event_end( span = self._event_map[event_id].span span.set_attribute("event_id", event_id) if payload is not None: - if event_type is CBEventType.QUERY: + if CBEventType.EXCEPTION in payload: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(payload[EventPayload.EXCEPTION]) + elif event_type is CBEventType.QUERY: pass elif event_type is CBEventType.RETRIEVE: for i, node_with_score in enumerate(payload[EventPayload.NODES]): @@ -163,8 +166,8 @@ def on_event_end( span.set_attribute(f"query.node.{i}.score", score) span.set_attribute(f"query.node.{i}.text", node.text) elif event_type is CBEventType.EMBEDDING: - texts = payload[EventPayload.CHUNKS] - vectors = payload[EventPayload.EMBEDDINGS] + texts = payload.get(EventPayload.CHUNKS, []) + vectors = payload.get(EventPayload.EMBEDDINGS, []) total_chunk_tokens = 0 for text, vector in zip(texts, vectors) : span.set_attribute(f"embedding_text_{texts.index(text)}", text) @@ -188,9 +191,7 @@ def on_event_end( span.set_attribute("total_tokens_used", token_counts.total_token_count) elif event_type is CBEventType.NODE_PARSING: span.set_attribute("node_parsing.num_nodes", len(payload[EventPayload.NODES])) - elif event_type is CBEventType.EXCEPTION: - span.set_status(Status(StatusCode.ERROR)) - span.record_exception(payload[EventPayload.EXCEPTION]) + if self._event_map[event_id].thread_identity == threading.get_ident(): detach(self._event_map[event_id].token) self._event_map.pop(event_id, None)