, ,

Gen AI on OpenShift Series — Episode 3

Building Generative AI Containers with Podman

Authors: Bobby Johns, David Kypuros, and Jason Nagin

Series Index

In this series, we will be offering our practical advice on implementing Generative AI (GenAI) solutions using containers (Podman) and on a container orchestration platform (OpenShift). In this series, we will cover:

  1. Introduction to Generative AI and Containerization with Podman and OpenShift
  2. Preparing Your AI Lab Environment with Podman and OpenShift
  3. Building Generative AI Containers with Podman
  4. Setting Up a Vector Database with Podman and OpenShift
  5. Leveraging LangChain and CamelK for Business Value
  6. Business Benefits of the AI Lab Environment

In this 6 part series, we will incorporate practical examples, code snippets, and best practices throughout the articles. Additionally, we will emphasize the importance of a well-structured AI lab environment in achieving business objectives, showcasing how each component contributes to these goals.

David Kypuros and I Presenting on Gen AI at Red Hat Summit Connect DFW. Followed by John Archer (Red Hat) and Lindi Sabloff (Guise.ai)

Episode 3: Building a Generative AI Containers with Podman

In this episode, we delve into the exciting world of Generative AI in containers as we explore “Building Generative AI Containers in Podman.” This guide takes you on a journey to create self-contained, shareable, and powerful Generative AI environments using Podman containers. Whether you’re a seasoned AI professional or just getting started, we provide insights and tools to simplify your AI adventures.

Prerequisites: Ensure you have a Fedora system with Python, pip, and Podman installed. If you completed the tasks in the previous post, “Preparing Your AI Lab Environment with Podman and OpenShift” you should have the required setup. Specifically setting up Podman.

We will be using the OpenAI API so you’ll need an OpenAI account and an API Key. The free one will be fine, but a paid account also works.

Python Virtual Environment

We start by creating a Python virtual environment to manage dependencies. This step offers benefits such as isolation, version management, efficient dependency management, sandboxing, portability, easy cleanup, and development isolation.

# Create Python Virtual Environment with chromadb



python -m venv venv-chroma

source venv-chroma/bin/activate

pip install chromadb langchain beautifulsoup4 lxml openai

image from xkcd

ChromaDB Container

Next, we build a ChromaDB container from the Git source. The Containerfile defines the container image creation process, emphasizing best practices for building containers.

mkdir chroma-container



cd chroma-container

mkdir bin

touch bin/container_entrypoint.sh

chmod +x bin/container_entrypoint.sh

touch requirements.txt

touch Containerfile

Insert the following text block into the Containerfile.

cat <<EOF > Containerfile



FROM python:3.10-slim-bookworm as builder

RUN apt-get update --fix-missing && apt-get install -y --fix-missing

build-essential

gcc

git

g++ &&

rm -rf /var/lib/apt/lists/*

RUN mkdir /install

WORKDIR /install

COPY ./requirements.txt requirements.txt

RUN git clone https://github.com/chroma-core/chroma.git /chroma-git

RUN pip install --no-cache-dir --upgrade --prefix="/install" -r requirements.txt

FROM python:3.10-slim-bookworm as final

RUN apt-get update --fix-missing && apt-get install -y --fix-missing

build-essential

gcc

g++ &&

rm -rf /var/lib/apt/lists/*

RUN mkdir /chroma

WORKDIR /chroma

COPY --from=builder /install /usr/local

COPY --from=builder /chroma-git /chroma

COPY ./bin/container_entrypoint.sh /container_entrypoint.sh

# Ensure the entrypoint script is executable

RUN chmod +x /container_entrypoint.sh

EXPOSE 8000

CMD ["/container_entrypoint.sh"]

EOF

This Containerfile is used to build a container image for a Python application.

What does this Containerfile define?

This Containerfile first creates a builder stage to install dependencies, clone a Git repository, and install Python packages. Then, in the final stage, it copies the necessary components from the builder stage, exposes a port, and sets the default command to run a Container entrypoint script. The purpose of this Containerfile is to create a containerized environment for a Python application based on the Chroma project without including all the temporary artifacts of the build process in the final container image. For more best practices on building containers see: Best practices for building images that pass Red Hat Container Certification

Requirements.txt and Entry Point

Create a file named “requirements.txt”

cat <<EOF > requirements.txt



chromadb

chroma-hnswlib==0.7.2

fastapi>=0.95.2, <0.100.0

graphlib_backport==1.0.3; python_version < '3.9'

importlib-resources

numpy==1.21.6

onnxruntime==1.14.1

overrides==7.3.1

posthog==2.4.0

pulsar-client==3.1.0

pydantic>=1.9,<2.0

pypika==0.48.9

requests==2.28.1

tokenizers==0.13.2

tqdm==4.65.0

typing_extensions==4.5.0

uvicorn[standard]==0.18.3

EOF

Create the container_entrypoint.sh file

cat <<EOF > bin/container_entrypoint.sh



#!/bin/bash

export IS_PERSISTENT=1

uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers

EOF

What is uvicorn, and why are we using it? uvicorn is a lightweight ASGI server designed for running Python web applications. It’s chosen for its speed, efficiency, ASGI support, compatibility, automatic workers, and WebSockets support.

Create volumes for ChromaDB and Flowise

# Create ChromaDB volumes



podman volume create chromadb-chroma

podman volume create chromadb-index_data

# Create a volume for Flowise

podman volume create flowise-volume

Building and Running ChromaDB Container

To build the ChromaDB container

# Build ChromaDB container



podman build . -t localhost/chroma/build

This will build the container image and store it in the local Podman registry. Expect output similar to this:

Output from Podman build

Start a ChromaDB Server

Start a ChromaDB Server in a Container with Podman.

podman run -d --rm



--name chromadb

-p 8000:8000

-v chromadb-chroma:/chroma

-v chromadb-index_data:/index_data

localhost/chroma/build

Start a Flowise Server

Start a Flowise Server in a Container with Podman

Because Flowise has a published version available on docker.io, we don’t have to create our own container image.

# Run Flowise server



podman run -d --rm --name flowise -p 3000:3000 flowiseai/flowise flowise start

You should be able to hit the URL of your ChromaDB with:

http://localhost:8000/api/v1/collections/

And the URL of your Flowise with:

http://localhost:3000/

Getting started with Flowise

(Be sure to add your OpenAI API credentials in Flowise as “OpenAI API” under the “Credetials” menu item.)

Create a collection name in your chromadb server to hold your local data.

cat <<EOF > collection_create.json



import chromadb

# Create a persistent Chroma client with the location of your Chroma DB.

persistent_client = chromadb.PersistentClient(path="http://localhost:8000/api/v1/")

# Create a collection called "test_collection".

collection = persistent_client.create_collection("dfw_summit_collection")

# Print a statement that the new collection exists.

print(f"Collection name: {collection.name}")

EOF

Below is a condensed JSON representation of a Flowise ChatFlow. Copy and paste this into your terminal window in the bash shell and it will create a file you can use to import the ChatFlow into your Flowise Web UI. (You can paste this into an IDE text editor and format the JSON into something more readable if you’re curious, but it’s not required.)

cat <<EOF > summit_2024_chatflow.json



{"nodes":[{"width":300,"height":330,"id":"openAIEmbeddings_0","position":{"x":-485.7532561700214,"y":420.8761308382209},"type":"customNode","data":{"id":"openAIEmbeddings_0","label":"OpenAI Embeddings","version":1,"name":"openAIEmbeddings","type":"OpenAIEmbeddings","baseClasses":["OpenAIEmbeddings","Embeddings"],"category":"Embeddings","description":"OpenAI API to generate embeddings for a given text","inputParams":[{"label":"Connect Credential","name":"credential","type":"credential","credentialNames":["openAIApi"],"id":"openAIEmbeddings_0-input-credential-credential"},{"label":"Strip New Lines","name":"stripNewLines","type":"boolean","optional":true,"additionalParams":true,"id":"openAIEmbeddings_0-input-stripNewLines-boolean"},{"label":"Batch Size","name":"batchSize","type":"number","optional":true,"additionalParams":true,"id":"openAIEmbeddings_0-input-batchSize-number"},{"label":"Timeout","name":"timeout","type":"number","optional":true,"additionalParams":true,"id":"openAIEmbeddings_0-input-timeout-number"},{"label":"BasePath","name":"basepath","type":"string","optional":true,"additionalParams":true,"id":"openAIEmbeddings_0-input-basepath-string"}],"inputAnchors":[],"inputs":{"stripNewLines":"","batchSize":"","timeout":"","basepath":""},"outputAnchors":[{"id":"openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings","name":"openAIEmbeddings","label":"OpenAIEmbeddings","type":"OpenAIEmbeddings | Embeddings"}],"outputs":{},"selected":false},"selected":false,"positionAbsolute":{"x":-485.7532561700214,"y":420.8761308382209},"dragging":false},{"width":300,"height":481,"id":"conversationalRetrievalQAChain_0","position":{"x":870.3499023746608,"y":1008.5688576728237},"type":"customNode","data":{"id":"conversationalRetrievalQAChain_0","label":"Conversational Retrieval QA Chain","version":1,"name":"conversationalRetrievalQAChain","type":"ConversationalRetrievalQAChain","baseClasses":["ConversationalRetrievalQAChain","BaseChain","Runnable"],"category":"Chains","description":"Document QA - built on RetrievalQAChain to provide a chat history component","inputParams":[{"label":"Return Source Documents","name":"returnSourceDocuments","type":"boolean","optional":true,"id":"conversationalRetrievalQAChain_0-input-returnSourceDocuments-boolean"},{"label":"System Message","name":"systemMessagePrompt","type":"string","rows":4,"additionalParams":true,"optional":true,"placeholder":"I want you to act as a document that I am having a conversation with. Your name is "AI Assistant". You will provide me with answers from the given info. If the answer is not included, say exactly "Hmm, I am not sure." and stop after that. Refuse to answer any question not about the info. Never break character.","id":"conversationalRetrievalQAChain_0-input-systemMessagePrompt-string"},{"label":"Chain Option","name":"chainOption","type":"options","options":[{"label":"MapReduceDocumentsChain","name":"map_reduce","description":"Suitable for QA tasks over larger documents and can run the preprocessing step in parallel, reducing the running time"},{"label":"RefineDocumentsChain","name":"refine","description":"Suitable for QA tasks over a large number of documents."},{"label":"StuffDocumentsChain","name":"stuff","description":"Suitable for QA tasks over a small number of documents."}],"additionalParams":true,"optional":true,"id":"conversationalRetrievalQAChain_0-input-chainOption-options"}],"inputAnchors":[{"label":"Language Model","name":"model","type":"BaseLanguageModel","id":"conversationalRetrievalQAChain_0-input-model-BaseLanguageModel"},{"label":"Vector Store Retriever","name":"vectorStoreRetriever","type":"BaseRetriever","id":"conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever"},{"label":"Memory","name":"memory","type":"BaseMemory","optional":true,"description":"If left empty, a default BufferMemory will be used","id":"conversationalRetrievalQAChain_0-input-memory-BaseMemory"}],"inputs":{"model":"{{chatOpenAI_0.data.instance}}","vectorStoreRetriever":"{{chromaUpsert_0.data.instance}}","memory":"{{bufferWindowMemory_0.data.instance}}","returnSourceDocuments":"","systemMessagePrompt":"","chainOption":""},"outputAnchors":[{"id":"conversationalRetrievalQAChain_0-output-conversationalRetrievalQAChain-ConversationalRetrievalQAChain|BaseChain|Runnable","name":"conversationalRetrievalQAChain","label":"ConversationalRetrievalQAChain","type":"ConversationalRetrievalQAChain | BaseChain | Runnable"}],"outputs":{},"selected":false},"selected":false,"positionAbsolute":{"x":870.3499023746608,"y":1008.5688576728237},"dragging":false},{"width":300,"height":525,"id":"chatOpenAI_0","position":{"x":487.1671554326233,"y":425.5277080326421},"type":"customNode","data":{"id":"chatOpenAI_0","label":"ChatOpenAI","version":1,"name":"chatOpenAI","type":"ChatOpenAI","baseClasses":["ChatOpenAI","BaseChatModel","BaseLanguageModel","Runnable"],"category":"Chat Models","description":"Wrapper around OpenAI large language models that use the Chat endpoint","inputParams":[{"label":"Connect Credential","name":"credential","type":"credential","credentialNames":["openAIApi"],"id":"chatOpenAI_0-input-credential-credential"},{"label":"Model Name","name":"modelName","type":"options","options":[{"label":"gpt-4","name":"gpt-4"},{"label":"gpt-4-0613","name":"gpt-4-0613"},{"label":"gpt-4-32k","name":"gpt-4-32k"},{"label":"gpt-4-32k-0613","name":"gpt-4-32k-0613"},{"label":"gpt-3.5-turbo","name":"gpt-3.5-turbo"},{"label":"gpt-3.5-turbo-0613","name":"gpt-3.5-turbo-0613"},{"label":"gpt-3.5-turbo-16k","name":"gpt-3.5-turbo-16k"},{"label":"gpt-3.5-turbo-16k-0613","name":"gpt-3.5-turbo-16k-0613"}],"default":"gpt-3.5-turbo","optional":true,"id":"chatOpenAI_0-input-modelName-options"},{"label":"Temperature","name":"temperature","type":"number","step":0.1,"default":0.9,"optional":true,"id":"chatOpenAI_0-input-temperature-number"},{"label":"Max Tokens","name":"maxTokens","type":"number","step":1,"optional":true,"additionalParams":true,"id":"chatOpenAI_0-input-maxTokens-number"},{"label":"Top Probability","name":"topP","type":"number","step":0.1,"optional":true,"additionalParams":true,"id":"chatOpenAI_0-input-topP-number"},{"label":"Frequency Penalty","name":"frequencyPenalty","type":"number","step":0.1,"optional":true,"additionalParams":true,"id":"chatOpenAI_0-input-frequencyPenalty-number"},{"label":"Presence Penalty","name":"presencePenalty","type":"number","step":0.1,"optional":true,"additionalParams":true,"id":"chatOpenAI_0-input-presencePenalty-number"},{"label":"Timeout","name":"timeout","type":"number","step":1,"optional":true,"additionalParams":true,"id":"chatOpenAI_0-input-timeout-number"},{"label":"BasePath","name":"basepath","type":"string","optional":true,"additionalParams":true,"id":"chatOpenAI_0-input-basepath-string"}],"inputAnchors":[],"inputs":{"modelName":"gpt-4","temperature":"0.5","maxTokens":"","topP":"","frequencyPenalty":"","presencePenalty":"","timeout":"","basepath":""},"outputAnchors":[{"id":"chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable","name":"chatOpenAI","label":"ChatOpenAI","type":"ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable"}],"outputs":{},"selected":false},"selected":false,"positionAbsolute":{"x":487.1671554326233,"y":425.5277080326421},"dragging":false},{"width":300,"height":382,"id":"cheerioWebScraper_0","position":{"x":-484.52998308596824,"y":992.0633791221885},"type":"customNode","data":{"id":"cheerioWebScraper_0","label":"Cheerio Web Scraper","version":1,"name":"cheerioWebScraper","type":"Document","baseClasses":["Document"],"category":"Document Loaders","description":"Load data from webpages","inputParams":[{"label":"URL","name":"url","type":"string","id":"cheerioWebScraper_0-input-url-string"},{"label":"Get Relative Links Method","name":"relativeLinksMethod","type":"options","description":"Select a method to retrieve relative links","options":[{"label":"Web Crawl","name":"webCrawl","description":"Crawl relative links from HTML URL"},{"label":"Scrape XML Sitemap","name":"scrapeXMLSitemap","description":"Scrape relative links from XML sitemap URL"}],"optional":true,"additionalParams":true,"id":"cheerioWebScraper_0-input-relativeLinksMethod-options"},{"label":"Get Relative Links Limit","name":"limit","type":"number","optional":true,"additionalParams":true,"description":"Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.","warning":"Retreiving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)","id":"cheerioWebScraper_0-input-limit-number"},{"label":"Metadata","name":"metadata","type":"json","optional":true,"additionalParams":true,"id":"cheerioWebScraper_0-input-metadata-json"}],"inputAnchors":[{"label":"Text Splitter","name":"textSplitter","type":"TextSplitter","optional":true,"id":"cheerioWebScraper_0-input-textSplitter-TextSplitter"}],"inputs":{"url":"https://access.redhat.com/documentation/en-us/openshift_container_platform/4.13/html-single/about/index","textSplitter":"{{recursiveCharacterTextSplitter_0.data.instance}}","relativeLinksMethod":"","limit":"","metadata":""},"outputAnchors":[{"id":"cheerioWebScraper_0-output-cheerioWebScraper-Document","name":"cheerioWebScraper","label":"Document","type":"Document"}],"outputs":{},"selected":false},"selected":false,"positionAbsolute":{"x":-484.52998308596824,"y":992.0633791221885},"dragging":false},{"width":300,"height":378,"id":"recursiveCharacterTextSplitter_0","position":{"x":-892.5751212048638,"y":791.1088186200254},"type":"customNode","data":{"id":"recursiveCharacterTextSplitter_0","label":"Recursive Character Text Splitter","version":1,"name":"recursiveCharacterTextSplitter","type":"RecursiveCharacterTextSplitter","baseClasses":["RecursiveCharacterTextSplitter","TextSplitter","BaseDocumentTransformer","Runnable"],"category":"Text Splitters","description":"Split documents recursively by different characters - starting with "\n\n", then "\n", then " "","inputParams":[{"label":"Chunk Size","name":"chunkSize","type":"number","default":1000,"optional":true,"id":"recursiveCharacterTextSplitter_0-input-chunkSize-number"},{"label":"Chunk Overlap","name":"chunkOverlap","type":"number","optional":true,"id":"recursiveCharacterTextSplitter_0-input-chunkOverlap-number"}],"inputAnchors":[],"inputs":{"chunkSize":1000,"chunkOverlap":""},"outputAnchors":[{"id":"recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable","name":"recursiveCharacterTextSplitter","label":"RecursiveCharacterTextSplitter","type":"RecursiveCharacterTextSplitter | TextSplitter | BaseDocumentTransformer | Runnable"}],"outputs":{},"selected":false},"selected":false,"positionAbsolute":{"x":-892.5751212048638,"y":791.1088186200254},"dragging":false},{"width":300,"height":656,"id":"chromaUpsert_0","position":{"x":-47.33876367286601,"y":653.0484335422038},"type":"customNode","data":{"id":"chromaUpsert_0","label":"Chroma Upsert Document","version":1,"name":"chromaUpsert","type":"Chroma","baseClasses":["Chroma","VectorStoreRetriever","BaseRetriever"],"category":"Vector Stores","description":"Upsert documents to Chroma","inputParams":[{"label":"Connect Credential","name":"credential","type":"credential","description":"Only needed if you have chroma on cloud services with X-Api-key","optional":true,"credentialNames":["chromaApi"],"id":"chromaUpsert_0-input-credential-credential"},{"label":"Collection Name","name":"collectionName","type":"string","id":"chromaUpsert_0-input-collectionName-string"},{"label":"Chroma URL","name":"chromaURL","type":"string","optional":true,"id":"chromaUpsert_0-input-chromaURL-string"},{"label":"Top K","name":"topK","description":"Number of top results to fetch. Default to 4","placeholder":"4","type":"number","additionalParams":true,"optional":true,"id":"chromaUpsert_0-input-topK-number"}],"inputAnchors":[{"label":"Document","name":"document","type":"Document","list":true,"id":"chromaUpsert_0-input-document-Document"},{"label":"Embeddings","name":"embeddings","type":"Embeddings","id":"chromaUpsert_0-input-embeddings-Embeddings"}],"inputs":{"document":["{{cheerioWebScraper_0.data.instance}}"],"embeddings":"{{openAIEmbeddings_0.data.instance}}","collectionName":"dfw_summit_collection","chromaURL":"http://192.168.68.73:8000","topK":""},"outputAnchors":[{"name":"output","label":"Output","type":"options","options":[{"id":"chromaUpsert_0-output-retriever-Chroma|VectorStoreRetriever|BaseRetriever","name":"retriever","label":"Chroma Retriever","type":"Chroma | VectorStoreRetriever | BaseRetriever"},{"id":"chromaUpsert_0-output-vectorStore-Chroma|VectorStore","name":"vectorStore","label":"Chroma Vector Store","type":"Chroma | VectorStore"}],"default":"retriever"}],"outputs":{"output":"retriever"},"selected":false},"selected":false,"positionAbsolute":{"x":-47.33876367286601,"y":653.0484335422038},"dragging":false},{"width":300,"height":476,"id":"bufferWindowMemory_0","position":{"x":426.6685584276553,"y":1225.5388303315713},"type":"customNode","data":{"id":"bufferWindowMemory_0","label":"Buffer Window Memory","version":1,"name":"bufferWindowMemory","type":"BufferWindowMemory","baseClasses":["BufferWindowMemory","BaseChatMemory","BaseMemory"],"category":"Memory","description":"Uses a window of size k to surface the last k back-and-forths to use as memory","inputParams":[{"label":"Memory Key","name":"memoryKey","type":"string","default":"chat_history","id":"bufferWindowMemory_0-input-memoryKey-string"},{"label":"Input Key","name":"inputKey","type":"string","default":"input","id":"bufferWindowMemory_0-input-inputKey-string"},{"label":"Size","name":"k","type":"number","default":"4","description":"Window of size k to surface the last k back-and-forths to use as memory.","id":"bufferWindowMemory_0-input-k-number"}],"inputAnchors":[],"inputs":{"memoryKey":"chat_history","inputKey":"input","k":"10"},"outputAnchors":[{"id":"bufferWindowMemory_0-output-bufferWindowMemory-BufferWindowMemory|BaseChatMemory|BaseMemory","name":"bufferWindowMemory","label":"BufferWindowMemory","type":"BufferWindowMemory | BaseChatMemory | BaseMemory"}],"outputs":{},"selected":false},"selected":false,"positionAbsolute":{"x":426.6685584276553,"y":1225.5388303315713},"dragging":false}],"edges":[{"source":"chatOpenAI_0","sourceHandle":"chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable","target":"conversationalRetrievalQAChain_0","targetHandle":"conversationalRetrievalQAChain_0-input-model-BaseLanguageModel","type":"buttonedge","id":"chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-model-BaseLanguageModel","data":{"label":""}},{"source":"recursiveCharacterTextSplitter_0","sourceHandle":"recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable","target":"cheerioWebScraper_0","targetHandle":"cheerioWebScraper_0-input-textSplitter-TextSplitter","type":"buttonedge","id":"recursiveCharacterTextSplitter_0-recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable-cheerioWebScraper_0-cheerioWebScraper_0-input-textSplitter-TextSplitter","data":{"label":""}},{"source":"cheerioWebScraper_0","sourceHandle":"cheerioWebScraper_0-output-cheerioWebScraper-Document","target":"chromaUpsert_0","targetHandle":"chromaUpsert_0-input-document-Document","type":"buttonedge","id":"cheerioWebScraper_0-cheerioWebScraper_0-output-cheerioWebScraper-Document-chromaUpsert_0-chromaUpsert_0-input-document-Document","data":{"label":""}},{"source":"openAIEmbeddings_0","sourceHandle":"openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings","target":"chromaUpsert_0","targetHandle":"chromaUpsert_0-input-embeddings-Embeddings","type":"buttonedge","id":"openAIEmbeddings_0-openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-chromaUpsert_0-chromaUpsert_0-input-embeddings-Embeddings","data":{"label":""}},{"source":"chromaUpsert_0","sourceHandle":"chromaUpsert_0-output-retriever-Chroma|VectorStoreRetriever|BaseRetriever","target":"conversationalRetrievalQAChain_0","targetHandle":"conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever","type":"buttonedge","id":"chromaUpsert_0-chromaUpsert_0-output-retriever-Chroma|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever","data":{"label":""}},{"source":"bufferWindowMemory_0","sourceHandle":"bufferWindowMemory_0-output-bufferWindowMemory-BufferWindowMemory|BaseChatMemory|BaseMemory","target":"conversationalRetrievalQAChain_0","targetHandle":"conversationalRetrievalQAChain_0-input-memory-BaseMemory","type":"buttonedge","id":"bufferWindowMemory_0-bufferWindowMemory_0-output-bufferWindowMemory-BufferWindowMemory|BaseChatMemory|BaseMemory-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-memory-BaseMemory","data":{"label":""}}]}

EOF

With the above file, you can add a new ChatFlow to Flowise:

  • Click the “+Add” button on the Flowsie homepage
  • Click the “gear” button and select “Load Flow”
  • Select the above file (dfw_summit_chatflow.json) you created
  • Click the “disk” icon to save and name your ChatFlow.

With these 2 servers running (ChromaDB & Flowise), you can ask questions about your local data with the Chatbot app and webpage.

Click the “dialog balloon” to start your ChatBot.

You can change the URL in the Cheerios component to any web page to use that data instead. I’ll leave it for you to experiment with other web pages.

Summary

In Episode 3: Building a Generative AI Containers with Podman we did the following:

Explored creating Generative AI environments in containers using Podman. Requires a Fedora system with Python, pip, and Podman installed.

Create a local Python virtual environment with Python packages: chromadb, langchain, beautifulsoup4, lxml, & openai installed. Also explained the benefits of using a PVE.

Built a chromadb container from Git source using a Containerfile. Included requirements.txt file with specified Python package versions for ChromaDB. Added a container_entrypoint.sh to define the entry point for the container, using uvicorn to run the ChromaDB application. Explaned the use of uvicorn as a lightweight ASGI server suitable for running Python web applications.

Created volumes for ChromaDB (chromadb-chroma and chromadb-index_data) and Flowise (flowise-volume).

Started a ChromaDB server and. Flowsie Server running in containers with Podman

Created your first Flowise ChatFlow using our ChromaDB as a local data source. Interact with the ChatBot app and webpage to ask questions about local data.

Next in the Series — Generative AI on OpenShift Series — Episode 4 — Setting Up a Vector Database with Podman and OpenShift

Episode 4 Topics:

  • OpenShift Deployment Dynamics: Learn about scaling, load balancing, and high availability configurations.
  • Integrate Flowise container insights for improved operational visibility.
  • Monitoring Mastery: Dive into effective monitoring and logging practices for containers on OpenShift.
  • Secure Containers, Smart Storage: Enhance security with access controls and OpenShift storage management for Vector Database containers. Ensure a robust and fortified data environment.
  • OpenShift Ecosystem Insights: Leverage OpenShift Operators for efficient orchestration and explore storage solutions.
  • Optimizing Performance: Explore resource management, CPU and memory considerations, and container optimization.

Helpful links:

Red Hat Developers Website — Excellent source for developers of all stripes. Great articles and focus on creating something useful in a short amount of time.

Podman — Everything you need to run Podman on your local development system, be it Linux, Windows, or Mac OS.

OpenShift, OpenShift AI/ML, and OpenShift Data Science — Power tools for container orchestration and building business tools that provide a competitive advantage.

Epic discussion of GenAI on OpenShift 4. by David Kypuros, Bobby Johns, and Jason Nagin.


cd ~ — back to all posts