diff --git a/example-apps/chatbot-rag-app/.flaskenv b/example-apps/chatbot-rag-app/.flaskenv deleted file mode 100644 index 88612f8d..00000000 --- a/example-apps/chatbot-rag-app/.flaskenv +++ /dev/null @@ -1,4 +0,0 @@ -FLASK_APP=api/app.py -FLASK_RUN_PORT=4000 -# Production mode ensures we don't run into problems. -FLASK_ENV=production diff --git a/example-apps/chatbot-rag-app/Dockerfile b/example-apps/chatbot-rag-app/Dockerfile index 317ebd69..bca2b036 100644 --- a/example-apps/chatbot-rag-app/Dockerfile +++ b/example-apps/chatbot-rag-app/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine AS build-step +FROM node:22-alpine AS build-step WORKDIR /app ENV PATH=/node_modules/.bin:$PATH COPY frontend ./frontend @@ -28,7 +28,4 @@ COPY api ./api COPY data ./data EXPOSE 4000 -# The only thing different from running local is that in docker we need to -# listen on all IPs, not just localhost. -ENV FLASK_RUN_HOST=0.0.0.0 -CMD [ "flask", "run"] +CMD [ "python", "api/app.py"] diff --git a/example-apps/chatbot-rag-app/README.md b/example-apps/chatbot-rag-app/README.md index 0419fae4..a4b5abfa 100644 --- a/example-apps/chatbot-rag-app/README.md +++ b/example-apps/chatbot-rag-app/README.md @@ -67,6 +67,12 @@ docker compose up --build --force-recreate *Note*: First time creating the index can fail on timeout. Wait a few minutes and retry. +Clean up when finished, like this: + +```bash +docker compose down +``` + ### Run locally If you want to run this example with Python and Node.js, you need to do a few @@ -95,9 +101,8 @@ correct packages installed: ```bash python3 -m venv .venv source .venv/bin/activate -# install dev requirements for pip-compile and dotenv -pip install pip-tools "python-dotenv[cli]" -pip-compile +# Install dotenv which is a portable way to load environment variables. +pip install "python-dotenv[cli]" pip install -r requirements.txt ``` @@ -105,7 +110,7 @@ pip install -r requirements.txt First, ingest the data into elasticsearch: ```bash -$ dotenv run -- flask create-index +$ dotenv run -- flask --app api/app.py create-index ".elser_model_2" model not available, downloading it now Model downloaded, starting deployment Loading data from ./data/data.json @@ -121,13 +126,30 @@ and retry. Now, run the app, which listens on http://localhost:4000 ```bash -$ dotenv run -- flask run - * Serving Flask app 'api/app.py' +$ dotenv run -- python api/app.py + * Serving Flask app 'app' * Debug mode: off ``` ## Customizing the app +### Updating package versions + +To update package versions, recreate [requirements.txt](requirements.txt) and +reinstall like this. Once checked in, any commands above will use updates. + +```bash +rm -rf .venv +python3 -m venv .venv +source .venv/bin/activate +# Install dev requirements for pip-compile +pip install pip-tools +# Recreate requirements.txt +pip-compile +# Install main dependencies +pip install -r requirements.txt +``` + ### Indexing your own data The ingesting logic is stored in [data/index_data.py](data/index_data.py). This diff --git a/example-apps/chatbot-rag-app/api/app.py b/example-apps/chatbot-rag-app/api/app.py index 826b6349..a94f4a24 100644 --- a/example-apps/chatbot-rag-app/api/app.py +++ b/example-apps/chatbot-rag-app/api/app.py @@ -37,6 +37,5 @@ def create_index(): index_data.main() -# Unless we run through flask, we can miss critical settings or telemetry signals. if __name__ == "__main__": - raise RuntimeError("Run via the parent directory: 'flask run'") + app.run(host="0.0.0.0", port=4000, debug=False) diff --git a/example-apps/chatbot-rag-app/docker-compose.yml b/example-apps/chatbot-rag-app/docker-compose.yml index 634fa831..87996b95 100644 --- a/example-apps/chatbot-rag-app/docker-compose.yml +++ b/example-apps/chatbot-rag-app/docker-compose.yml @@ -4,9 +4,10 @@ services: context: . container_name: ingest-data restart: 'no' + environment: + FLASK_APP: api/app.py env_file: - .env - - .flaskenv command: flask create-index api-frontend: @@ -18,6 +19,5 @@ services: context: . env_file: - .env - - .flaskenv ports: - "4000:4000" diff --git a/example-apps/chatbot-rag-app/env.example b/example-apps/chatbot-rag-app/env.example index d078293f..169c3c96 100644 --- a/example-apps/chatbot-rag-app/env.example +++ b/example-apps/chatbot-rag-app/env.example @@ -28,10 +28,10 @@ ES_INDEX_CHAT_HISTORY=workplace-app-docs-chat-history # Uncomment and complete if you want to use Bedrock LLM # LLM_TYPE=bedrock -# AWS_ACCESS_KEY= -# AWS_SECRET_KEY= -# AWS_REGION= -# AWS_MODEL_ID= +# AWS_ACCESS_KEY_ID= +# AWS_SECRET_ACCESS_KEY= +# AWS_DEFAULT_REGION= +# CHAT_MODEL=amazon.titan-text-lite-v1 # Uncomment and complete if you want to use Vertex AI # LLM_TYPE=vertex diff --git a/example-apps/chatbot-rag-app/llm_integrations.py b/example-apps/chatbot-rag-app/llm_integrations.py new file mode 100644 index 00000000..1131b2e8 --- /dev/null +++ b/example-apps/chatbot-rag-app/llm_integrations.py @@ -0,0 +1,69 @@ +import os + +import vertexai +from langchain_aws import ChatBedrock +from langchain_cohere import ChatCohere +from langchain_google_vertexai import ChatVertexAI +from langchain_mistralai import ChatMistralAI +from langchain_openai import AzureChatOpenAI, ChatOpenAI + +LLM_TYPE = os.getenv("LLM_TYPE", "openai") + + +def init_openai_chat(temperature): + return ChatOpenAI(model=os.getenv("CHAT_MODEL"), streaming=True, temperature=temperature) + + +def init_vertex_chat(temperature): + VERTEX_PROJECT_ID = os.getenv("VERTEX_PROJECT_ID") + VERTEX_REGION = os.getenv("VERTEX_REGION", "us-central1") + vertexai.init(project=VERTEX_PROJECT_ID, location=VERTEX_REGION) + return ChatVertexAI(streaming=True, temperature=temperature) + + +def init_azure_chat(temperature): + return AzureChatOpenAI(model=os.getenv("CHAT_DEPLOYMENT"), streaming=True, temperature=temperature) + + +def init_bedrock(temperature): + return ChatBedrock(model_id=os.getenv("CHAT_MODEL"), streaming=True, model_kwargs={"temperature": temperature}) + + +def init_mistral_chat(temperature): + MISTRAL_API_ENDPOINT = os.getenv("MISTRAL_API_ENDPOINT") + MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") + MISTRAL_MODEL = os.getenv("MISTRAL_MODEL", "Mistral-large") + kwargs = { + "mistral_api_key": MISTRAL_API_KEY, + "temperature": temperature, + } + if MISTRAL_API_ENDPOINT: + kwargs["endpoint"] = MISTRAL_API_ENDPOINT + if MISTRAL_MODEL: + kwargs["model"] = MISTRAL_MODEL + return ChatMistralAI(**kwargs) + + +def init_cohere_chat(temperature): + COHERE_API_KEY = os.getenv("COHERE_API_KEY") + COHERE_MODEL = os.getenv("COHERE_MODEL") + return ChatCohere(cohere_api_key=COHERE_API_KEY, model=COHERE_MODEL, temperature=temperature) + + +MAP_LLM_TYPE_TO_CHAT_MODEL = { + "azure": init_azure_chat, + "bedrock": init_bedrock, + "openai": init_openai_chat, + "vertex": init_vertex_chat, + "mistral": init_mistral_chat, + "cohere": init_cohere_chat, +} + + +def get_llm(temperature=0): + if LLM_TYPE not in MAP_LLM_TYPE_TO_CHAT_MODEL: + raise Exception( + "LLM type not found. Please set LLM_TYPE to one of: " + ", ".join(MAP_LLM_TYPE_TO_CHAT_MODEL.keys()) + "." + ) + + return MAP_LLM_TYPE_TO_CHAT_MODEL[LLM_TYPE](temperature=temperature) diff --git a/example-apps/chatbot-rag-app/requirements.txt b/example-apps/chatbot-rag-app/requirements.txt index 21fea6a1..2e2f2f04 100644 --- a/example-apps/chatbot-rag-app/requirements.txt +++ b/example-apps/chatbot-rag-app/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.13 # by the following command: # # pip-compile @@ -352,7 +352,6 @@ types-requests==2.32.0.20241016 # via cohere typing-extensions==4.12.2 # via - # anyio # cohere # huggingface-hub # langchain-core