diff --git a/.env.example b/.env.example
index 081c9026..5d231931 100644
--- a/.env.example
+++ b/.env.example
@@ -40,13 +40,28 @@ GOOGLE_OAUTH_CLIENT_SECRET=
MICROSOFT_GRAPH_OAUTH_CLIENT_ID=
MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET=
+# AWS Access Key ID and Secret Access Key with access to your S3 instance
+AWS_ACCESS_KEY_ID=
+AWS_SECRET_ACCESS_KEY=
+
# OPTIONAL: dns routable from google (etc.) to handle continous ingest (something like ngrok works). This enables continous ingestion
WEBHOOK_BASE_URL=
+# Model Provider API Keys
OPENAI_API_KEY=
+ANTHROPIC_API_KEY=
+OLLAMA_ENDPOINT=
+WATSONX_API_KEY=
+WATSONX_ENDPOINT=
+WATSONX_PROJECT_ID=
-AWS_ACCESS_KEY_ID=
-AWS_SECRET_ACCESS_KEY=
+# LLM Provider configuration. Providers can be "anthropic", "watsonx", "ibm" or "ollama".
+LLM_PROVIDER=
+LLM_MODEL=
+
+# Embedding provider configuration. Providers can be "watsonx", "ibm" or "ollama".
+EMBEDDING_PROVIDER=
+EMBEDDING_MODEL=
# OPTIONAL url for openrag link to langflow in the UI
LANGFLOW_PUBLIC_URL=
diff --git a/.github/workflows/build-multiarch.yml b/.github/workflows/build-multiarch.yml
index f9a83400..336f8df9 100644
--- a/.github/workflows/build-multiarch.yml
+++ b/.github/workflows/build-multiarch.yml
@@ -14,6 +14,7 @@ jobs:
outputs:
skip_release: ${{ steps.version.outputs.skip_release }}
version: ${{ steps.version.outputs.version }}
+ docker_version: ${{ steps.version.outputs.docker_version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- name: Checkout
@@ -26,6 +27,12 @@ jobs:
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"
+ # Normalize version per PEP 440 for Docker tags
+ # e.g., "0.1.53-rc2" -> "0.1.53rc2" to match Python's importlib.metadata
+ DOCKER_VERSION=$(echo "$VERSION" | sed -E 's/-?(rc|alpha|beta|dev|post)/\1/g')
+ echo "docker_version=$DOCKER_VERSION" >> $GITHUB_OUTPUT
+ echo "Docker Version: $DOCKER_VERSION"
+
# Check if tag already exists
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists, skipping release"
@@ -117,13 +124,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Extract version from pyproject.toml
- id: version
- run: |
- VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
- echo "Version: $VERSION"
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -141,7 +141,7 @@ jobs:
file: ${{ matrix.file }}
platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'pull_request' }}
- tags: ${{ matrix.tag }}:${{ steps.version.outputs.version }}-${{ matrix.arch }}
+ tags: ${{ matrix.tag }}:${{ needs.check-version.outputs.docker_version }}-${{ matrix.arch }}
cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.arch }}
@@ -153,12 +153,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Extract version from pyproject.toml
- id: version
- run: |
- VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
-
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
@@ -167,7 +161,7 @@ jobs:
- name: Create and push multi-arch manifests
run: |
- VERSION=${{ steps.version.outputs.version }}
+ VERSION=${{ needs.check-version.outputs.docker_version }}
# Create versioned tags
docker buildx imagetools create -t langflowai/openrag-backend:$VERSION \
@@ -224,13 +218,6 @@ jobs:
- name: Install uv
uses: astral-sh/setup-uv@v3
- - name: Extract version from pyproject.toml
- id: version
- run: |
- VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
- echo "version=$VERSION" >> $GITHUB_OUTPUT
- echo "Version: $VERSION"
-
- name: Build wheel and source distribution
run: |
uv build
@@ -253,8 +240,8 @@ jobs:
- name: Create Release
uses: softprops/action-gh-release@v2
with:
- tag_name: v${{ steps.version.outputs.version }}
- name: Release ${{ steps.version.outputs.version }}
+ tag_name: v${{ needs.check-version.outputs.version }}
+ name: Release ${{ needs.check-version.outputs.version }}
draft: false
prerelease: ${{ needs.check-version.outputs.is_prerelease }}
generate_release_notes: true
diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml
index a70dd24d..544b846e 100644
--- a/.github/workflows/test-integration.yml
+++ b/.github/workflows/test-integration.yml
@@ -38,8 +38,12 @@ jobs:
docker builder prune -af || true
docker-compose -f docker-compose.yml down -v --remove-orphans || true
+ - name: Cleanup OpenSearch data (root-owned files)
+ run: |
+ docker run --rm -v $(pwd):/work alpine rm -rf /work/opensearch-data || true
+
- run: df -h
-
+
- name: Checkout
uses: actions/checkout@v4
diff --git a/docker-compose.yml b/docker-compose.yml
index a0b1ca2b..2a73da89 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -80,10 +80,11 @@ services:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
volumes:
- - ./openrag-documents:/app/openrag-documents:Z
- - ./keys:/app/keys:Z
- - ./flows:/app/flows:U,z
- - ./config:/app/config:Z
+ - ${OPENRAG_DOCUMENTS_PATH:-./openrag-documents}:/app/openrag-documents:Z
+ - ${OPENRAG_KEYS_PATH:-./keys}:/app/keys:Z
+ - ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z
+ - ${OPENRAG_CONFIG_PATH:-./config}:/app/config:Z
+ - ${OPENRAG_DATA_PATH:-./data}:/app/data:Z
openrag-frontend:
image: langflowai/openrag-frontend:${OPENRAG_VERSION:-latest}
@@ -100,7 +101,7 @@ services:
langflow:
volumes:
- - ./flows:/app/flows:U,z
+ - ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z
image: langflowai/openrag-langflow:${OPENRAG_VERSION:-latest}
build:
context: .
diff --git a/docs/docs/_partial-docker-compose-down-and-prune.mdx b/docs/docs/_partial-docker-compose-down-and-prune.mdx
new file mode 100644
index 00000000..179c0525
--- /dev/null
+++ b/docs/docs/_partial-docker-compose-down-and-prune.mdx
@@ -0,0 +1,9 @@
+```bash title="Docker"
+docker compose down --volumes --remove-orphans --rmi local
+docker system prune -f
+```
+
+```bash title="Podman"
+podman compose down --volumes --remove-orphans --rmi local
+podman system prune -f
+```
\ No newline at end of file
diff --git a/docs/docs/_partial-docker-compose-up.mdx b/docs/docs/_partial-docker-compose-up.mdx
new file mode 100644
index 00000000..535effb3
--- /dev/null
+++ b/docs/docs/_partial-docker-compose-up.mdx
@@ -0,0 +1,7 @@
+```bash title="Docker"
+docker compose up -d
+```
+
+```bash title="Podman"
+podman compose up -d
+```
\ No newline at end of file
diff --git a/docs/docs/_partial-docker-remove-and-cleanup-steps.mdx b/docs/docs/_partial-docker-remove-and-cleanup-steps.mdx
new file mode 100644
index 00000000..ccc91713
--- /dev/null
+++ b/docs/docs/_partial-docker-remove-and-cleanup-steps.mdx
@@ -0,0 +1,49 @@
+2. Remove all containers, including stopped containers:
+
+ ```bash title="Docker"
+ docker rm --force $(docker ps -aq)
+ ```
+
+ ```bash title="Podman"
+ podman rm --all --force
+ ```
+
+3. Remove all images:
+
+ ```bash title="Docker"
+ docker rmi --force $(docker images -q)
+ ```
+
+ ```bash title="Podman"
+ podman rmi --all --force
+ ```
+
+4. Remove all volumes:
+
+ ```bash title="Docker"
+ docker volume prune --force
+ ```
+
+ ```bash title="Podman"
+ podman volume prune --force
+ ```
+
+5. Remove all networks except the default network:
+
+ ```bash title="Docker"
+ docker network prune --force
+ ```
+
+ ```bash title="Podman"
+ podman network prune --force
+ ```
+
+6. Clean up any leftover data:
+
+ ```bash title="Docker"
+ docker system prune --all --force --volumes
+ ```
+
+ ```bash title="Podman"
+ podman system prune --all --force --volumes
+ ```
\ No newline at end of file
diff --git a/docs/docs/_partial-docker-stop-all.mdx b/docs/docs/_partial-docker-stop-all.mdx
new file mode 100644
index 00000000..3fbf17f9
--- /dev/null
+++ b/docs/docs/_partial-docker-stop-all.mdx
@@ -0,0 +1,7 @@
+```bash title="Docker"
+docker stop $(docker ps -q)
+```
+
+```bash title="Podman"
+podman stop --all
+```
\ No newline at end of file
diff --git a/docs/docs/_partial-factory-reset-warning.mdx b/docs/docs/_partial-factory-reset-warning.mdx
new file mode 100644
index 00000000..97f2ca7e
--- /dev/null
+++ b/docs/docs/_partial-factory-reset-warning.mdx
@@ -0,0 +1,25 @@
+:::warning
+This is a destructive action that does the following:
+
+* Destroys all OpenRAG containers, volumes, and local images with `docker compose down --volumes --remove-orphans --rmi local`.
+* Prunes any additional container objects with `docker system prune -f`.
+* Deletes the contents of OpenRAG's `config` and `./opensearch-data` directories.
+* Deletes the `conversations.json` file.
+
+
Destroyed containers and deleted data are lost and cannot be recovered after running this operation.
+
+This operation _doesn't_ remove the `.env` file or the contents of the `./openrag-documents` directory.
+:::
+
+
\ No newline at end of file
diff --git a/docs/docs/_partial-install-next-steps.mdx b/docs/docs/_partial-install-next-steps.mdx
new file mode 100644
index 00000000..ad5938be
--- /dev/null
+++ b/docs/docs/_partial-install-next-steps.mdx
@@ -0,0 +1,5 @@
+## Next steps
+
+* Try some of OpenRAG's core features in the [quickstart](/quickstart#chat-with-documents).
+* Learn how to [manage OpenRAG services](/manage-services).
+* [Upload documents](/ingestion), and then use the [**Chat**](/chat) to explore your data.
\ No newline at end of file
diff --git a/docs/docs/_partial-integrate-chat.mdx b/docs/docs/_partial-integrate-chat.mdx
index de3d9a62..867ecd27 100644
--- a/docs/docs/_partial-integrate-chat.mdx
+++ b/docs/docs/_partial-integrate-chat.mdx
@@ -4,8 +4,8 @@ import TabItem from '@theme/TabItem';
1. Open the **OpenRAG OpenSearch Agent** flow in the Langflow visual editor: From the **Chat** window, click **Settings**, click **Edit in Langflow**, and then click **Proceed**.
-2. Create a [Langflow API key](https://docs.langflow.org/api-keys-and-authentication), which is a user-specific token required to send requests to the Langflow server.
-This key doesn't grant access to OpenRAG.
+2. Optional: If you don't want to use the Langflow API key that is generated automatically when you install OpenRAG, you can create a [Langflow API key](https://docs.langflow.org/api-keys-and-authentication).
+This key doesn't grant access to OpenRAG; it is only for authenticating with the Langflow API.
1. In the Langflow visual editor, click your user icon in the header, and then select **Settings**.
2. Click **Langflow API Keys**, and then click **Add New**.
diff --git a/docs/docs/_partial-ollama.mdx b/docs/docs/_partial-ollama.mdx
deleted file mode 100644
index a5164e97..00000000
--- a/docs/docs/_partial-ollama.mdx
+++ /dev/null
@@ -1,24 +0,0 @@
-import Icon from "@site/src/components/icon/icon";
-
-Using Ollama for your OpenRAG language model provider offers greater flexibility and configuration, but can also be overwhelming to start.
-These recommendations are a reasonable starting point for users with at least one GPU and experience running LLMs locally.
-
-For best performance, OpenRAG recommends OpenAI's `gpt-oss:20b` language model. However, this model uses 16GB of RAM, so consider using Ollama Cloud or running Ollama on a remote machine.
-
-For generating embeddings, OpenRAG recommends the [`nomic-embed-text`](https://ollama.com/library/nomic-embed-text) embedding model, which provides high-quality embeddings optimized for retrieval tasks.
-
-To run models in [**Ollama Cloud**](https://docs.ollama.com/cloud), follow these steps:
-
- 1. Sign in to Ollama Cloud.
- In a terminal, enter `ollama signin` to connect your local environment with Ollama Cloud.
- 2. To run the model, in Ollama, select the `gpt-oss:20b-cloud` model, or run `ollama run gpt-oss:20b-cloud` in a terminal.
- Ollama Cloud models are run at the same URL as your local Ollama server at `http://localhost:11434`, and automatically offloaded to Ollama's cloud service.
- 3. Connect OpenRAG to the same local Ollama server as you would for local models in onboarding, using the default address of `http://localhost:11434`.
- 4. In the **Language model** field, select the `gpt-oss:20b-cloud` model.
-
-To run models on a **remote Ollama server**, follow these steps:
-
- 1. Ensure your remote Ollama server is accessible from your OpenRAG instance.
- 2. In the **Ollama Base URL** field, enter your remote Ollama server's base URL, such as `http://your-remote-server:11434`.
- OpenRAG connects to the remote Ollama server and populates the lists with the server's available models.
- 3. Select your **Embedding model** and **Language model** from the available options.
\ No newline at end of file
diff --git a/docs/docs/_partial-onboarding.mdx b/docs/docs/_partial-onboarding.mdx
index 28680853..ce1f1939 100644
--- a/docs/docs/_partial-onboarding.mdx
+++ b/docs/docs/_partial-onboarding.mdx
@@ -1,79 +1,134 @@
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-import PartialOllama from '@site/docs/_partial-ollama.mdx';
-## Application onboarding
+## Complete the application onboarding process {#application-onboarding}
-The first time you start OpenRAG, regardless of how you installed it, you must complete application onboarding.
+The first time you start the OpenRAG application, you must complete the application onboarding process to select language and embedding models that are essential for OpenRAG features like the [**Chat**](/chat).
Some of these variables, such as the embedding models, can be changed seamlessly after onboarding.
Others are immutable and require you to destroy and recreate the OpenRAG containers.
-For more information, see [Environment variables](/reference/configuration).
+For more information, see the [OpenRAG environment variables reference](/reference/configuration).
-You can use different providers for your language model and embedding model, such as Anthropic for the language model and OpenAI for the embeddings model.
+You can use different providers for your language model and embedding model, such as Anthropic for the language model and OpenAI for the embedding model.
Additionally, you can set multiple embedding models.
You only need to complete onboarding for your preferred providers.
-
-
+
+
- :::info
- Anthropic doesn't provide embedding models. If you select Anthropic for your language model, you must select a different provider for embeddings.
- :::
+:::info
+Anthropic doesn't provide embedding models. If you select Anthropic for your language model, you must select a different provider for the embedding model.
+:::
- 1. Enable **Use environment Anthropic API key** to automatically use your key from the `.env` file.
- Alternatively, paste an Anthropic API key into the field.
- 2. Under **Advanced settings**, select your **Language Model**.
- 3. Click **Complete**.
- 4. In the second onboarding panel, select a provider for embeddings and select your **Embedding Model**.
- 5. To complete the onboarding tasks, click **What is OpenRAG**, and then click **Add a Document**.
- Alternatively, click **Skip overview**.
- 6. Continue with the [Quickstart](/quickstart).
+1. Enter your Anthropic API key, or enable **Get API key from environment variable** to pull the key from your [OpenRAG `.env` file](/reference/configuration).
-
-
+ If you set `ANTHROPIC_API_KEY` in your OpenRAG `.env` file, this value can be populated automatically.
- 1. Enable **Get API key from environment variable** to automatically enter your key from the TUI-generated `.env` file.
- Alternatively, paste an OpenAI API key into the field.
- 2. Under **Advanced settings**, select your **Language Model**.
- 3. Click **Complete**.
- 4. In the second onboarding panel, select a provider for embeddings and select your **Embedding Model**.
- 5. To complete the onboarding tasks, click **What is OpenRAG**, and then click **Add a Document**.
- Alternatively, click **Skip overview**.
- 6. Continue with the [Quickstart](/quickstart).
+2. Under **Advanced settings**, select the language model that you want to use.
-
-
+3. Click **Complete**.
- 1. Complete the fields for **watsonx.ai API Endpoint**, **IBM Project ID**, and **IBM API key**.
- These values are found in your IBM watsonx deployment.
- 2. Under **Advanced settings**, select your **Language Model**.
- 3. Click **Complete**.
- 4. In the second onboarding panel, select a provider for embeddings and select your **Embedding Model**.
- 5. To complete the onboarding tasks, click **What is OpenRAG**, and then click **Add a Document**.
- Alternatively, click **Skip overview**.
- 6. Continue with the [Quickstart](/quickstart).
+4. Select a provider for embeddings, provide the required information, and then select the embedding model you want to use.
+For information about another provider's credentials and settings, see the instructions for that provider.
-
-
+5. Click **Complete**.
- :::info
- Ollama isn't installed with OpenRAG. To install Ollama, see the [Ollama documentation](https://docs.ollama.com/).
- :::
+ After you configure the embedding model, OpenRAG uses your credentials and models to ingest some [initial documents](/knowledge#default-documents). This tests the connection, and it allows you to ask OpenRAG about itself in the [**Chat**](/chat).
+ If there is a problem with the model configuration, an error occurs and you are redirected back to the application onboarding screen.
+ Verify that the credential is valid and has access to the selected model, and then click **Complete** to retry ingestion.
- 1. To connect to an Ollama server running on your local machine, enter your Ollama server's base URL address.
- The default Ollama server address is `http://localhost:11434`.
- OpenRAG connects to the Ollama server and populates the model lists with the server's available models.
- 2. Select the **Embedding Model** and **Language Model** your Ollama server is running.
-
- Ollama model selection and external server configuration
-
-
- 3. Click **Complete**.
- 4. To complete the onboarding tasks, click **What is OpenRAG**, and then click **Add a Document**.
- 5. Continue with the [Quickstart](/quickstart).
+6. Continue through the overview slides for a brief introduction to OpenRAG, or click **Skip overview**.
+The overview demonstrates some basic functionality that is covered in the [quickstart](/quickstart#chat-with-documents) and in other parts of the OpenRAG documentation.
-
-
\ No newline at end of file
+
+
+
+1. Use the values from your IBM watsonx deployment for the **watsonx.ai API Endpoint**, **IBM Project ID**, and **IBM API key** fields.
+
+ If you set `WATSONX_API_KEY`, `WATSONX_API_URL`, or `WATSONX_PROJECT_ID` in your [OpenRAG `.env` file](/reference/configuration), these values can be populated automatically.
+
+2. Under **Advanced settings**, select the language model that you want to use.
+
+3. Click **Complete**.
+
+4. Select a provider for embeddings, provide the required information, and then select the embedding model you want to use.
+For information about another provider's credentials and settings, see the instructions for that provider.
+
+5. Click **Complete**.
+
+ After you configure the embedding model, OpenRAG uses your credentials and models to ingest some [initial documents](/knowledge#default-documents). This tests the connection, and it allows you to ask OpenRAG about itself in the [**Chat**](/chat).
+ If there is a problem with the model configuration, an error occurs and you are redirected back to the application onboarding screen.
+ Verify that the credentials are valid and have access to the selected model, and then click **Complete** to retry ingestion.
+
+6. Continue through the overview slides for a brief introduction to OpenRAG, or click **Skip overview**.
+The overview demonstrates some basic functionality that is covered in the [quickstart](/quickstart#chat-with-documents) and in other parts of the OpenRAG documentation.
+
+
+
+
+:::info
+Ollama isn't installed with OpenRAG. You must install it separately if you want to use Ollama as a model provider.
+:::
+
+Using Ollama as your language and embedding model provider offers greater flexibility and configuration options for hosting models, but it can be advanced for new users.
+The recommendations given here are a reasonable starting point for users with at least one GPU and experience running LLMs locally.
+
+The OpenRAG team recommends the OpenAI `gpt-oss:20b` lanuage model and the [`nomic-embed-text`](https://ollama.com/library/nomic-embed-text) embedding model.
+However, `gpt-oss:20b` uses 16GB of RAM, so consider using Ollama Cloud or running Ollama on a remote machine.
+
+1. [Install Ollama locally or on a remote server](https://docs.ollama.com/), or [run models in Ollama Cloud](https://docs.ollama.com/cloud).
+
+ If you are running a remote server, it must be accessible from your OpenRAG deployment.
+
+2. In OpenRAG onboarding, connect to your Ollama server:
+
+ * **Local Ollama server**: Enter your Ollama server's base URL and port. The default Ollama server address is `http://localhost:11434`.
+ * **Ollama Cloud**: Because Ollama Cloud models run at the same address as a local Ollama server and automatically offload to Ollama's cloud service, you can use the same base URL and port as you would for a local Ollama server. The default address is `http://localhost:11434`.
+ * **Remote server**: Enter your remote Ollama server's base URL and port, such as `http://your-remote-server:11434`.
+
+ If the connection succeeds, OpenRAG populates the model lists with the server's available models.
+
+3. Select the model that your Ollama server is running.
+
+ Language model and embedding model selections are independent.
+ You can use the same or different servers for each model.
+
+ To use different providers for each model, you must configure both providers, and select the relevant model for each provider.
+
+4. Click **Complete**.
+
+ After you configure the embedding model, OpenRAG uses the address and models to ingest some [initial documents](/knowledge#default-documents). This tests the connection, and it allows you to ask OpenRAG about itself in the [**Chat**](/chat).
+ If there is a problem with the model configuration, an error occurs and you are redirected back to the application onboarding screen.
+ Verify that the server address is valid, and that the selected model is running on the server.
+ Then, click **Complete** to retry ingestion.
+
+5. Continue through the overview slides for a brief introduction to OpenRAG, or click **Skip overview**.
+The overview demonstrates some basic functionality that is covered in the [quickstart](/quickstart#chat-with-documents) and in other parts of the OpenRAG documentation.
+
+
+
+
+1. Enter your OpenAI API key, or enable **Get API key from environment variable** to pull the key from your [OpenRAG `.env` file](/reference/configuration).
+
+ If you set `OPENAI_API_KEY` in your OpenRAG `.env` file, this value can be populated automatically.
+
+2. Under **Advanced settings**, select the language model that you want to use.
+
+3. Click **Complete**.
+
+4. Select a provider for embeddings, provide the required information, and then select the embedding model you want to use.
+For information about another provider's credentials and settings, see the instructions for that provider.
+
+5. Click **Complete**.
+
+ After you configure the embedding model, OpenRAG uses your credentials and models to ingest some [initial documents](/knowledge#default-documents). This tests the connection, and it allows you to ask OpenRAG about itself in the [**Chat**](/chat).
+ If there is a problem with the model configuration, an error occurs and you are redirected back to the application onboarding screen.
+ Verify that the credential is valid and has access to the selected model, and then click **Complete** to retry ingestion.
+
+6. Continue through the overview slides for a brief introduction to OpenRAG, or click **Skip overview**.
+The overview demonstrates some basic functionality that is covered in the [quickstart](/quickstart#chat-with-documents) and in other parts of the OpenRAG documentation.
+
+
+
\ No newline at end of file
diff --git a/docs/docs/_partial-opensearch-auth-mode.mdx b/docs/docs/_partial-opensearch-auth-mode.mdx
new file mode 100644
index 00000000..e7b2ae99
--- /dev/null
+++ b/docs/docs/_partial-opensearch-auth-mode.mdx
@@ -0,0 +1,11 @@
+* **No-auth mode**: If you select **Basic Setup** in the [TUI](/tui), or your [OpenRAG `.env` file](/reference/configuration) doesn't include OAuth credentials, then the OpenRAG OpenSearch instance runs in no-auth mode.
+
+ This mode uses one anonymous JWT token for OpenSearch authentication.
+ There is no differentiation between users; all users that access your OpenRAG instance can access all documents uploaded to your knowledge base.
+
+* **OAuth mode**: If you select **Advanced Setup** in the [TUI](/tui), or your [OpenRAG `.env` file](/reference/configuration) includes OAuth credentials, then the OpenRAG OpenSearch instance runs in OAuth mode.
+
+ This mode uses a unique JWT token for each OpenRAG user, and each document is tagged with user ownership.
+ Documents are filtered by user owner; users see only the documents that they uploaded or have access to through their cloud storage accounts.
+
+ To enable OAuth mode after initial setup, see [Ingest files with OAuth connectors](/ingestion#oauth-ingestion).
\ No newline at end of file
diff --git a/docs/docs/_partial-prereq-common.mdx b/docs/docs/_partial-prereq-common.mdx
new file mode 100644
index 00000000..66374fcc
--- /dev/null
+++ b/docs/docs/_partial-prereq-common.mdx
@@ -0,0 +1,12 @@
+* Gather the credentials and connection details for your preferred model providers.
+You must have access to at least one language model and one embedding model.
+If a provider offers both types, you can use the same provider for both models.
+If a provider offers only one type, you must select two providers.
+
+ * **OpenAI**: Create an [OpenAI API key](https://platform.openai.com/api-keys).
+ * **Anthropic**: Create an [Anthropic API key](https://www.anthropic.com/docs/api/reference).
+ Anthropic provides language models only; you must select an additional provider for embeddings.
+ * **IBM watsonx.ai**: Get your watsonx.ai API endpoint, IBM project ID, and IBM API key from your watsonx deployment.
+ * **Ollama**: Deploy an [Ollama instance and models](https://docs.ollama.com/) locally, in the cloud, or on a remote server, and then get your Ollama server's base URL and the names of the models that you want to use.
+
+* Optional: Install GPU support with an NVIDIA GPU, [CUDA](https://docs.nvidia.com/cuda/) support, and compatible NVIDIA drivers on the OpenRAG host machine. If you don't have GPU capabilities, OpenRAG provides an alternate CPU-only deployment.
\ No newline at end of file
diff --git a/docs/docs/_partial-prereq-no-script.mdx b/docs/docs/_partial-prereq-no-script.mdx
new file mode 100644
index 00000000..a8fd8349
--- /dev/null
+++ b/docs/docs/_partial-prereq-no-script.mdx
@@ -0,0 +1,6 @@
+* Install [uv](https://docs.astral.sh/uv/getting-started/installation/).
+
+* Install [Podman](https://podman.io/docs/installation) (recommended) or [Docker](https://docs.docker.com/get-docker/).
+
+* Install [`podman-compose`](https://docs.podman.io/en/latest/markdown/podman-compose.1.html) or [Docker Compose](https://docs.docker.com/compose/install/).
+To use Docker Compose with Podman, you must alias Docker Compose commands to Podman commands.
\ No newline at end of file
diff --git a/docs/docs/_partial-prereq-python.mdx b/docs/docs/_partial-prereq-python.mdx
new file mode 100644
index 00000000..77036589
--- /dev/null
+++ b/docs/docs/_partial-prereq-python.mdx
@@ -0,0 +1 @@
+* Install [Python](https://www.python.org/downloads/release/python-3100/) version 3.13 or later.
\ No newline at end of file
diff --git a/docs/docs/_partial-prereq-windows.mdx b/docs/docs/_partial-prereq-windows.mdx
new file mode 100644
index 00000000..eeb671c1
--- /dev/null
+++ b/docs/docs/_partial-prereq-windows.mdx
@@ -0,0 +1,2 @@
+* For Microsoft Windows, you must use the Windows Subsystem for Linux (WSL).
+See [Install OpenRAG on Windows](/install-windows) before proceeding.
\ No newline at end of file
diff --git a/docs/docs/_partial-setup.mdx b/docs/docs/_partial-setup.mdx
new file mode 100644
index 00000000..9af2ecbf
--- /dev/null
+++ b/docs/docs/_partial-setup.mdx
@@ -0,0 +1,135 @@
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import PartialOpenSearchAuthMode from '@site/docs/_partial-opensearch-auth-mode.mdx';
+
+You can use either **Basic Setup** or **Advanced Setup** to configure OpenRAG.
+This choice determines how OpenRAG authenticates with your deployment's [OpenSearch instance](/knowledge), and it controls user access to documents stored in your OpenSearch knowledge base:
+
+
+
+:::info
+You must use **Advanced Setup** if you want to [use OAuth connectors to upload documents from cloud storage](/ingestion#oauth-ingestion).
+:::
+
+If OpenRAG detects OAuth credentials during setup, it recommends **Advanced Setup** in the TUI.
+
+
+
+
+1. In the TUI, click **Basic Setup** or press 1.
+
+2. Enter administrator passwords for the OpenRAG OpenSearch and Langflow services, or click **Generate Passwords** to generate passwords automatically.
+
+ The OpenSearch password is required.
+
+ The Langflow password is recommended but optional.
+ If the Langflow password is empty, the Langflow server starts without authentication enabled. For more information, see [Langflow settings](/reference/configuration#langflow-settings).
+
+3. Optional: Enter your OpenAI API key, or leave this field empty to provide model provider credentials during the application onboarding process.
+
+ There is no material difference between providing the key now or during the [application onboarding process](#application-onboarding).
+ If you provide a key now, it can be populated automatically during the application onboarding process if you select the OpenAI model provider, and then enable **Get API key from environment variable**.
+
+ OpenRAG's core functionality requires access to language and embedding models.
+ By default, OpenRAG uses OpenAI models.
+ If you aren't sure which models or providers to use, you must provide an OpenAI API key to use OpenRAG's default model configuration.
+ If you want to use a different model provider, you can leave this field empty.
+
+4. Click **Save Configuration**.
+
+ Your passwords and API key, if provided, are stored in the [OpenRAG `.env` file](/reference/configuration) in your OpenRAG installation directory.
+ If you modified any credentials that were pulled from an existing `.env` file, those values are updated in the `.env` file.
+
+5. Click **Start All Services** to start the OpenRAG services that run in containers.
+
+ This process can take some time while OpenRAG pulls and runs the container images.
+ If all services start successfully, the TUI prints a confirmation message:
+
+ ```text
+ Services started successfully
+ Command completed successfully
+ ```
+
+6. Under [**Native Services**](/manage-services), click **Start** to start the Docling service.
+
+7. Launch the OpenRAG application:
+
+ * From the TUI main menu, click **Open App**.
+ * In your browser, navigate to `localhost:3000`.
+
+8. Continue with the [application onboarding process](#application-onboarding).
+
+
+
+
+1. In the TUI, click **Advanced Setup** or press 2.
+
+2. Enter administrator passwords for the OpenRAG OpenSearch and Langflow services, or click **Generate Passwords** to generate passwords automatically.
+
+ The OpenSearch password is required.
+
+ The Langflow password is recommended but optional.
+ If the Langflow password is empty, the Langflow server starts without authentication enabled. For more information, see [Langflow settings](/reference/configuration#langflow-settings).
+
+3. Optional: Enter your OpenAI API key, or leave this field empty to provide model provider credentials during the application onboarding process.
+
+ There is no material difference between providing the key now or during the [application onboarding process](#application-onboarding).
+ If you provide a key now, it can be populated automatically during the application onboarding process if you select the OpenAI model provider, and then enable **Get API key from environment variable**.
+
+ OpenRAG's core functionality requires access to language and embedding models.
+ By default, OpenRAG uses OpenAI models.
+ If you aren't sure which models or providers to use, you must provide an OpenAI API key to use OpenRAG's default model configuration.
+ If you want to use a different model provider, you can leave this field empty.
+
+4. To upload documents from external storage, such as Google Drive, add the required OAuth credentials for the connectors that you want to use. These settings can be populated automatically if OpenRAG detects these credentials in an [OpenRAG `.env` file](/reference/configuration) in the OpenRAG installation directory.
+
+ * **Amazon**: Provide your AWS Access Key ID and AWS Secret Access Key with access to your S3 instance. For more information, see the AWS documentation on [Configuring access to AWS applications](https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html).
+ * **Google**: Provide your Google OAuth Client ID and Google OAuth Client Secret. You can generate these in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials). For more information, see the [Google OAuth client documentation](https://developers.google.com/identity/protocols/oauth2).
+ * **Microsoft**: For the Microsoft OAuth Client ID and Microsoft OAuth Client Secret, provide [Azure application registration credentials for SharePoint and OneDrive](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/app-registration?view=odsp-graph-online). For more information, see the [Microsoft Graph OAuth client documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth).
+
+ You can [manage OAuth credentials](/ingestion#oauth-ingestion) later, but it is recommended to configure them during initial set up.
+
+5. The OpenRAG TUI presents redirect URIs for your OAuth app.
+These are the URLs your OAuth provider will redirect back to after user sign-in.
+Register these redirect values with your OAuth provider as they are presented in the TUI.
+
+6. Click **Save Configuration**.
+
+ Your passwords, API key, and OAuth credentials, if provided, are stored in the [OpenRAG `.env` file](/reference/configuration) in your OpenRAG installation directory.
+ If you modified any credentials that were pulled from an existing `.env` file, those values are updated in the `.env` file.
+
+7. Click **Start All Services** to start the OpenRAG services that run in containers.
+
+ This process can take some time while OpenRAG pulls and runs the container images.
+ If all services start successfully, the TUI prints a confirmation message:
+
+ ```text
+ Services started successfully
+ Command completed successfully
+ ```
+
+8. Under [**Native Services**](/manage-services), click **Start** to start the Docling service.
+
+9. Launch the OpenRAG application:
+
+ * From the TUI main menu, click **Open App**.
+ * In your browser, navigate to `localhost:3000`.
+
+10. If you enabled OAuth connectors, you must sign in to your OAuth provider before being redirected to your OpenRAG instance.
+
+11. If required, you can edit the following additional environment variables.
+Only change these variables if your OpenRAG deployment has a non-default network configuration, such as a reverse proxy or custom domain.
+
+ * `LANGFLOW_PUBLIC_URL`: Sets the base address to access the Langflow web interface. This is where users interact with flows in a browser.
+ * `WEBHOOK_BASE_URL`: Sets the base address for the following OpenRAG OAuth connector endpoints:
+ * Amazon S3: Not applicable.
+ * Google Drive: `WEBHOOK_BASE_URL/connectors/google_drive/webhook`
+ * OneDrive: `WEBHOOK_BASE_URL/connectors/onedrive/webhook`
+ * SharePoint: `WEBHOOK_BASE_URL/connectors/sharepoint/webhook`
+
+12. Continue with the [application onboarding process](#application-onboarding).
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/core-components/agents.mdx b/docs/docs/core-components/agents.mdx
index 405dbd42..d242552d 100644
--- a/docs/docs/core-components/agents.mdx
+++ b/docs/docs/core-components/agents.mdx
@@ -4,8 +4,6 @@ slug: /agents
---
import Icon from "@site/src/components/icon/icon";
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
OpenRAG includes a built-in [Langflow](https://docs.langflow.org/) instance for creating and managing functional application workflows called _flows_.
In a flow, the individual workflow steps are represented by [_components_](https://docs.langflow.org/concepts-components) that are connected together to form a complete process.
@@ -34,7 +32,7 @@ For example, to view and edit the built-in **Chat** flow (the **OpenRAG OpenSear
If prompted to acknowledge that you are entering Langflow, click **Proceed**.
- If Langflow requests login information, enter the `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` from the `.env` file in your OpenRAG installation directory.
+ If Langflow requests login information, enter the `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` from your [OpenRAG `.env` file](/reference/configuration) in your OpenRAG installation directory.

@@ -65,7 +63,7 @@ Explore the [Langflow documentation](https://docs.langflow.org/) to learn more a
By default, OpenRAG is pinned to the latest Langflow Docker image for stability.
-If necessary, you can set a specific Langflow version with the [`LANGFLOW_VERSION`](/reference/configuration). However, there are risks to changing this setting:
+If necessary, you can set a specific Langflow version with the `LANGFLOW_VERSION` [environment variable](/reference/configuration). However, there are risks to changing this setting:
* The [Langflow documentation](https://docs.langflow.org/) describes the functionality present in the latest release of the Langflow OSS Python package. If your `LANGFLOW_VERSION` is different, the Langflow documentation might not align with the features and default settings in your OpenRAG installation.
diff --git a/docs/docs/core-components/ingestion.mdx b/docs/docs/core-components/ingestion.mdx
index 3e991176..7a69e3dd 100644
--- a/docs/docs/core-components/ingestion.mdx
+++ b/docs/docs/core-components/ingestion.mdx
@@ -8,6 +8,8 @@ import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialTempKnowledge from '@site/docs/_partial-temp-knowledge.mdx';
import PartialIngestionFlow from '@site/docs/_partial-ingestion-flow.mdx';
+import PartialDockerComposeUp from '@site/docs/_partial-docker-compose-up.mdx';
+import PartialDockerStopAll from '@site/docs/_partial-docker-stop-all.mdx';
Upload documents to your [OpenRAG OpenSearch instance](/knowledge) to populate your knowledge base with unique content, such as your own company documents, research papers, or websites.
Documents are processed through OpenRAG's knowledge ingestion flows with Docling.
@@ -62,56 +64,41 @@ Before users can connect their own cloud storage accounts, you must configure th
To enable multiple connectors, you must register an app and generate credentials for each provider.
-
-
-If you use the TUI to manage your OpenRAG containers, provide OAuth credentials in the **Advanced Setup**.
+
+If you use the [Terminal User Interface (TUI)](/tui) to manage your OpenRAG services, enter OAuth credentials in the **Advanced Setup** menu.
You can do this during [installation](/install#setup), or you can add the credentials afterwards:
-1. If OpenRAG is running, stop it: Go to [**Status**](/install#tui-container-management), and then click **Stop Services**.
+1. If OpenRAG is running, open the TUI's **Status** menu (3), and then click **Stop Services**.
-2. Click **Advanced Setup**, and then add the OAuth credentials for the cloud storage providers that you want to use:
+2. Open the **Advanced Setup** menu (2), and then add the OAuth credentials for the cloud storage providers that you want to use:
* **Amazon**: Provide your AWS Access Key ID and AWS Secret Access Key with access to your S3 instance. For more information, see the AWS documentation on [Configuring access to AWS applications](https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html).
* **Google**: Provide your Google OAuth Client ID and Google OAuth Client Secret. You can generate these in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials). For more information, see the [Google OAuth client documentation](https://developers.google.com/identity/protocols/oauth2).
* **Microsoft**: For the Microsoft OAuth Client ID and Microsoft OAuth Client Secret, provide [Azure application registration credentials for SharePoint and OneDrive](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/app-registration?view=odsp-graph-online). For more information, see the [Microsoft Graph OAuth client documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth).
-3. The OpenRAG TUI presents redirect URIs for your OAuth app that you must register with your OAuth provider.
+3. The TUI presents redirect URIs for your OAuth app that you must register with your OAuth provider.
These are the URLs your OAuth provider will redirect back to after users authenticate and grant access to their cloud storage.
-4. Click **Save Configuration**.
+4. Click **Save Configuration** to add the OAuth credentials to your [OpenRAG `.env` file](/reference/configuration).
- OpenRAG regenerates the [`.env`](/reference/configuration) file with the given credentials.
+5. Click **Start All Services** to restart the OpenRAG containers with OAuth enabled.
-5. Click **Start Container Services**.
+6. Launch the OpenRAG app.
+You should be prompted to sign in to your OAuth provider before being redirected to your OpenRAG instance.
-
+
-If you [install OpenRAG with self-managed containers](/docker), set OAuth credentials in the `.env` file for Docker Compose.
+If you [installed OpenRAG with self-managed services](/docker), set OAuth credentials in your [OpenRAG `.env` file](/reference/configuration).
-You can do this during [initial set up](/docker#install-openrag-with-docker-compose), or you can add the credentials afterwards:
+You can do this during [initial set up](/docker#setup), or you can add the credentials afterwards:
-1. Stop your OpenRAG deployment.
+1. Stop all OpenRAG containers:
-
-
+
- ```bash
- podman stop --all
- ```
-
-
-
-
- ```bash
- docker stop $(docker ps -q)
- ```
-
-
-
-
-2. Edit the `.env` file for Docker Compose to add the OAuth credentials for the cloud storage providers that you want to use:
+2. Edit your OpenRAG `.env` file to add the OAuth credentials for the cloud storage providers that you want to use:
* **Amazon**: Provide your AWS Access Key ID and AWS Secret Access Key with access to your S3 instance. For more information, see the AWS documentation on [Configuring access to AWS applications](https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html).
@@ -136,24 +123,9 @@ You can do this during [initial set up](/docker#install-openrag-with-docker-comp
3. Save the `.env` file.
-4. Restart your OpenRAG deployment:
+4. Restart your OpenRAG containers:
-
-
-
- ```bash
- podman-compose up -d
- ```
-
-
-
-
- ```bash
- docker-compose up -d
- ```
-
-
-
+
@@ -238,6 +210,7 @@ All errors were file-specific, and they didn't stop the pipeline.
* Machine: Apple M4 Pro
* Podman VM:
+
* Name: podman-machine-default
* Type: applehv
* vCPUs: 7
diff --git a/docs/docs/core-components/knowledge-filters.mdx b/docs/docs/core-components/knowledge-filters.mdx
index 7821f814..2197b5f7 100644
--- a/docs/docs/core-components/knowledge-filters.mdx
+++ b/docs/docs/core-components/knowledge-filters.mdx
@@ -4,8 +4,6 @@ slug: /knowledge-filters
---
import Icon from "@site/src/components/icon/icon";
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
OpenRAG's knowledge filters help you organize and manage your [knowledge base](/knowledge) by creating pre-defined views of your documents.
diff --git a/docs/docs/core-components/knowledge.mdx b/docs/docs/core-components/knowledge.mdx
index 3edf5a55..31c6d8a1 100644
--- a/docs/docs/core-components/knowledge.mdx
+++ b/docs/docs/core-components/knowledge.mdx
@@ -4,13 +4,12 @@ slug: /knowledge
---
import Icon from "@site/src/components/icon/icon";
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
+import PartialOpenSearchAuthMode from '@site/docs/_partial-opensearch-auth-mode.mdx';
OpenRAG includes a built-in [OpenSearch](https://docs.opensearch.org/latest/) instance that serves as the underlying datastore for your _knowledge_ (documents).
This specialized database is used to store and retrieve your documents and the associated vector data (embeddings).
-The documents in your OpenSearch knowledge base provide specialized context in addition to the general knowledge available to the language model that you select when you [install OpenRAG](/install) or [edit a flow](/agents).
+The documents in your OpenSearch knowledge base provide specialized context in addition to the general knowledge available to the language model that you select when you [install OpenRAG](/install-options) or [edit a flow](/agents).
You can [upload documents](/ingestion) from a variety of sources to populate your knowledge base with unique content, such as your own company documents, research papers, or websites.
Documents are processed through OpenRAG's knowledge ingestion flows with Docling.
@@ -26,26 +25,22 @@ The **Knowledge** page lists the documents OpenRAG has ingested into your OpenSe
To explore the raw contents of your knowledge base, click **Knowledge** to get a list of all ingested documents.
Click a document to view the chunks produced from splitting the document during ingestion.
-By default, OpenRAG includes some initial documents about OpenRAG. You can use these documents to ask OpenRAG about itself, and to test the [**Chat**](/chat) feature before uploading your own documents.
-If you [delete these documents](#delete-knowledge), you won't be able to ask OpenRAG about itself and it's own functionality.
+### Default documents {#default-documents}
+
+By default, OpenRAG includes some initial documents about OpenRAG.
+These documents are ingested automatically during the [application onboarding process](/install#application-onboarding).
+
+You can use these documents to ask OpenRAG about itself, and to test the [**Chat**](/chat) feature before uploading your own documents.
+
+If you [delete](#delete-knowledge) these documents, you won't be able to ask OpenRAG about itself and it's own functionality.
It is recommended that you keep these documents, and use [filters](/knowledge-filters) to separate them from your other knowledge.
## OpenSearch authentication and document access {#auth}
-When you [install OpenRAG](/install), you can choose between two setup modes: **Basic Setup** and **Advanced Setup**.
-The mode you choose determines how OpenRAG authenticates with OpenSearch and controls access to documents:
+When you [install OpenRAG](/install-options), you provide the initial configuration values for your OpenRAG services, including authentication credentials for OpenSearch and OAuth connectors.
+This configuration determines how OpenRAG authenticates with your deployment's OpenSearch instance, and it controls user access to documents in your knowledge base:
-* **Basic Setup (no-auth mode)**: If you choose **Basic Setup**, then OpenRAG is installed in no-auth mode.
-This mode uses one, anonymous JWT token for OpenSearch authentication.
-There is no differentiation between users.
-All users that access your OpenRAG instance can access all documents uploaded to your OpenSearch knowledge base.
-
-* **Advanced Setup (OAuth mode)**: If you choose **Advanced Setup**, then OpenRAG is installed in OAuth mode.
-This mode uses a unique JWT token for each OpenRAG user, and each document is tagged with user ownership. Documents are filtered by user owner.
-This means users see only the documents that they uploaded or have access to.
-
-You can enable OAuth mode after installation.
-For more information, see [Ingest files with OAuth connectors](/ingestion#oauth-ingestion).
+
## OpenSearch indexes
@@ -75,18 +70,18 @@ If needed, you can use [filters](/knowledge-filters) to separate documents that
### Set the embedding model and dimensions {#set-the-embedding-model-and-dimensions}
-When you [install OpenRAG](/install), you select at least one embedding model during [application onboarding](/install#application-onboarding).
+When you [install OpenRAG](/install-options), you select at least one embedding model during the [application onboarding process](/install#application-onboarding).
OpenRAG automatically detects and configures the appropriate vector dimensions for your selected embedding model, ensuring optimal search performance and compatibility.
In the OpenRAG repository, you can find the complete list of supported models in [`models_service.py`](https://github.com/langflow-ai/openrag/blob/main/src/services/models_service.py) and the corresponding vector dimensions in [`settings.py`](https://github.com/langflow-ai/openrag/blob/main/src/config/settings.py).
-During application onboarding, you can select from the supported models.
+During the application onboarding process, you can select from the supported models.
The default embedding dimension is `1536`, and the default model is the OpenAI `text-embedding-3-small`.
-If you want to use an unsupported model, you must manually set the model in your [OpenRAG configuration](/reference/configuration).
+If you want to use an unsupported model, you must manually set the model in your [OpenRAG `.env` file](/reference/configuration).
If you use an unsupported embedding model that doesn't have defined dimensions in `settings.py`, then OpenRAG falls back to the default dimensions (1536) and logs a warning. OpenRAG's OpenSearch instance and flows continue to work, but [similarity search](https://www.ibm.com/think/topics/vector-search) quality can be affected if the actual model dimensions aren't 1536.
-To change the embedding model after onboarding, it is recommended that you modify the embedding model setting in the OpenRAG **Settings** page or in your [OpenRAG configuration](/reference/configuration).
+To change the embedding model after onboarding, it is recommended that you modify the embedding model setting in the OpenRAG **Settings** page or in your [OpenRAG `.env` file](/reference/configuration).
This will automatically update all relevant [OpenRAG flows](/agents) to use the new embedding model configuration.
### Set Docling parameters
@@ -97,35 +92,26 @@ When you [upload documents](/ingestion), Docling processes the files, splits the
You can use either Docling Serve or OpenRAG's built-in Docling ingestion pipeline to process documents.
-
-
-
-By default, OpenRAG uses [Docling Serve](https://github.com/docling-project/docling-serve).
+* **Docling Serve ingestion**: By default, OpenRAG uses [Docling Serve](https://github.com/docling-project/docling-serve).
This means that OpenRAG starts a `docling serve` process on your local machine and runs Docling ingestion through an API service.
-
-
+* **Built-in Docling ingestion**: If you want to use OpenRAG's built-in Docling ingestion pipeline instead of the separate Docling Serve service, set `DISABLE_INGEST_WITH_LANGFLOW=true` in your [OpenRAG environment variables](/reference/configuration#document-processing-settings).
-If you want to use OpenRAG's built-in Docling ingestion pipeline instead of the separate Docling Serve service, set `DISABLE_INGEST_WITH_LANGFLOW=true` in your [OpenRAG environment variables](/reference/configuration#document-processing).
+ The built-in pipeline uses the Docling processor directly instead of through the Docling Serve API.
-The built-in pipeline uses the Docling processor directly instead of through the Docling Serve API.
-
-For the underlying functionality, see [`processors.py`](https://github.com/langflow-ai/openrag/blob/main/src/models/processors.py#L58) in the OpenRAG repository.
-
-
-
+ For the underlying functionality, see [`processors.py`](https://github.com/langflow-ai/openrag/blob/main/src/models/processors.py#L58) in the OpenRAG repository.
To modify the Docling ingestion and embedding parameters, click **Settings** in the OpenRAG user interface.
:::tip
OpenRAG warns you if `docling serve` isn't running.
-You can [start and stop OpenRAG services](/install#tui-container-management) from the TUI main menu with **Start Native Services** or **Stop Native Services**.
+For information about starting and stopping OpenRAG native services, like Docling, see [Manage OpenRAG services](/manage-services).
:::
* **Embedding model**: Select the model to use to generate vector embeddings for your documents.
This is initially set during installation.
- The recommended way to change this setting is in the OpenRAG **Settings** or your [OpenRAG configuration](/reference/configuration).
+ The recommended way to change this setting is in the OpenRAG **Settings** or your [OpenRAG `.env` file](/reference/configuration).
This will automatically update all relevant [OpenRAG flows](/agents) to use the new embedding model configuration.
If you uploaded documents prior to changing the embedding model, you can [create filters](/knowledge-filters) to separate documents embedded with different models, or you can reupload all documents to regenerate embeddings with the new model.
@@ -153,7 +139,7 @@ The default value is 200 characters, which represents an overlap of 20 percent i
The default path for local uploads is the `./openrag-documents` subdirectory in your OpenRAG installation directory. This is mounted to the `/app/openrag-documents/` directory inside the OpenRAG container. Files added to the host or container directory are visible in both locations.
-To change this location, modify the **Documents Paths** variable in either the [**Advanced Setup** menu](/install#setup) or in the `.env` used by Docker Compose.
+To change this location, modify the **Documents Paths** variable in either the [**Advanced Setup** menu](/install#setup) or in your [OpenRAG `.env` file](/reference/configuration).
## Delete knowledge {#delete-knowledge}
diff --git a/docs/docs/get-started/docker.mdx b/docs/docs/get-started/docker.mdx
index 64555bbb..9eca74f1 100644
--- a/docs/docs/get-started/docker.mdx
+++ b/docs/docs/get-started/docker.mdx
@@ -1,118 +1,111 @@
---
-title: Install OpenRAG containers
+title: Deploy OpenRAG with self-managed services
slug: /docker
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialOnboarding from '@site/docs/_partial-onboarding.mdx';
-import PartialWsl from '@site/docs/_partial-wsl-install.mdx';
+import PartialPrereqCommon from '@site/docs/_partial-prereq-common.mdx';
+import PartialPrereqNoScript from '@site/docs/_partial-prereq-no-script.mdx';
+import PartialPrereqWindows from '@site/docs/_partial-prereq-windows.mdx';
+import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx';
+import PartialInstallNextSteps from '@site/docs/_partial-install-next-steps.mdx';
-OpenRAG has two Docker Compose files. Both files deploy the same applications and containers locally, but they are for different environments:
+To manage your own OpenRAG services, deploy OpenRAG with Docker or Podman.
-- [`docker-compose.yml`](https://github.com/langflow-ai/openrag/blob/main/docker-compose.yml) is an OpenRAG deployment with GPU support for accelerated AI processing. This Docker Compose file requires an NVIDIA GPU with [CUDA](https://docs.nvidia.com/cuda/) support.
-
-- [`docker-compose-cpu.yml`](https://github.com/langflow-ai/openrag/blob/main/docker-compose-cpu.yml) is a CPU-only version of OpenRAG for systems without NVIDIA GPU support. Use this Docker Compose file for environments where GPU drivers aren't available.
+Use this installation method if you don't want to [use the Terminal User Interface (TUI)](/tui), or you need to run OpenRAG in an environment where using the TUI is unfeasible.
## Prerequisites
-- Install the following:
+
- - [Python](https://www.python.org/downloads/release/python-3100/) version 3.13 or later.
- - [uv](https://docs.astral.sh/uv/getting-started/installation/).
- - [Podman](https://podman.io/docs/installation) (recommended) or [Docker](https://docs.docker.com/get-docker/).
- - [`podman-compose`](https://docs.podman.io/en/latest/markdown/podman-compose.1.html) or [Docker Compose](https://docs.docker.com/compose/install/). To use Docker Compose with Podman, you must alias Docker Compose commands to Podman commands.
+
-- Microsoft Windows only: To run OpenRAG on Windows, you must use the Windows Subsystem for Linux (WSL).
+
-
- Install WSL for OpenRAG
+
-
+## Prepare your deployment {#setup}
-
+1. Clone the OpenRAG repository:
-- Prepare model providers and credentials.
-
- During [application onboarding](#application-onboarding), you must select language model and embedding model providers.
- If your chosen provider offers both types, you can use the same provider for both selections.
- If your provider offers only one type, such as Anthropic, you must select two providers.
-
- Gather the credentials and connection details for your chosen model providers before starting onboarding:
-
- - OpenAI: Create an [OpenAI API key](https://platform.openai.com/api-keys).
- - Anthropic language models: Create an [Anthropic API key](https://www.anthropic.com/docs/api/reference).
- - IBM watsonx.ai: Get your watsonx.ai API endpoint, IBM project ID, and IBM API key from your watsonx deployment.
- - Ollama: Use the [Ollama documentation](https://docs.ollama.com/) to set up your Ollama instance locally, in the cloud, or on a remote server, and then get your Ollama server's base URL.
-
-- Optional: Install GPU support with an NVIDIA GPU, [CUDA](https://docs.nvidia.com/cuda/) support, and compatible NVIDIA drivers on the OpenRAG host machine. This is required to use the GPU-accelerated Docker Compose file. If you choose not to use GPU support, you must use the CPU-only Docker Compose file instead.
-
-## Install OpenRAG with Docker Compose
-
-To install OpenRAG with Docker Compose, do the following:
-
-1. Clone the OpenRAG repository.
```bash
git clone https://github.com/langflow-ai/openrag.git
+ ```
+
+2. Change to the root of the cloned repository:
+
+ ```bash
cd openrag
```
-2. Install dependencies.
+3. Install dependencies:
+
```bash
uv sync
```
-3. Copy the example `.env` file included in the repository root.
- The example file includes all environment variables with comments to guide you in finding and setting their values.
+4. Create a `.env` file at the root of the cloned repository.
+
+ You can create an empty file or copy the repository's [`.env.example`](https://github.com/langflow-ai/openrag/blob/main/.env.example) file.
+ The example file contains some of the [OpenRAG environment variables](/reference/configuration) to get you started with configuring your deployment.
+
```bash
cp .env.example .env
```
- Alternatively, create a new `.env` file in the repository root.
- ```
- touch .env
- ```
+5. Edit the `.env` file to configure your deployment using [OpenRAG environment variables](/reference/configuration).
+The OpenRAG Docker Compose files pull values from your `.env` file to configure the OpenRAG containers.
+The following variables are required or recommended:
-4. The Docker Compose files are populated with the values from your `.env` file.
- The `OPENSEARCH_PASSWORD` value must be set.
- `OPENSEARCH_PASSWORD` can be automatically generated when using the TUI, but for a Docker Compose installation, you can set it manually instead. To generate an OpenSearch admin password, see the [OpenSearch documentation](https://docs.opensearch.org/latest/security/configuration/demo-configuration/#setting-up-a-custom-admin-password).
+ * **`OPENSEARCH_PASSWORD` (Required)**: Sets the OpenSearch administrator password. It must adhere to the [OpenSearch password complexity requirements](https://docs.opensearch.org/latest/security/configuration/demo-configuration/#setting-up-a-custom-admin-password).
- The following values are optional:
+ * **`LANGFLOW_SUPERUSER`**: The username for the Langflow administrator user. If `LANGFLOW_SUPERUSER` isn't set, then the default value is `admin`.
- ```bash
- OPENAI_API_KEY=your_openai_api_key
- LANGFLOW_SECRET_KEY=your_secret_key
- ```
+ * **`LANGFLOW_SUPERUSER_PASSWORD` (Strongly recommended)**: Sets the Langflow administrator password, and determines the Langflow server's default authentication mode. If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then the Langflow server starts without authentication enabled. For more information, see [Langflow settings](/reference/configuration#langflow-settings).
- `OPENAI_API_KEY` is optional. You can provide it during [application onboarding](#application-onboarding) or choose a different model provider. If you want to set it in your `.env` file, you can find your OpenAI API key in your [OpenAI account](https://platform.openai.com/api-keys).
+ * **`LANGFLOW_SECRET_KEY` (Strongly recommended)**: A secret encryption key for internal Langflow operations. It is recommended to [generate your own Langflow secret key](https://docs.langflow.org/api-keys-and-authentication#langflow-secret-key). If `LANGFLOW_SECRET_KEY` isn't set, then Langflow generates a secret key automatically.
- `LANGFLOW_SECRET_KEY` is optional. Langflow will auto-generate it if not set. For more information, see the [Langflow documentation](https://docs.langflow.org/api-keys-and-authentication#langflow-secret-key).
+ * **Model provider credentials**: Provide credentials for your preferred model providers. If none of these are set in the `.env` file, you must configure at least one provider during the [application onboarding process](#application-onboarding).
- The following Langflow configuration values are optional but important to consider:
+ * `OPENAI_API_KEY`
+ * `ANTHROPIC_API_KEY`
+ * `OLLAMA_ENDPOINT`
+ * `WATSONX_API_KEY`
+ * `WATSONX_ENDPOINT`
+ * `WATSONX_PROJECT_ID`
- ```bash
- LANGFLOW_SUPERUSER=admin
- LANGFLOW_SUPERUSER_PASSWORD=your_langflow_password
- ```
+ * **OAuth provider credentials**: To upload documents from external storage, such as Google Drive, set the required OAuth credentials for the connectors that you want to use. You can [manage OAuth credentials](/ingestion#oauth-ingestion) later, but it is recommended to configure them during initial set up so you don't have to rebuild the containers.
- `LANGFLOW_SUPERUSER` defaults to `admin`. You can omit it or set it to a different username. `LANGFLOW_SUPERUSER_PASSWORD` is optional. If omitted, Langflow runs in [autologin mode](https://docs.langflow.org/api-keys-and-authentication#langflow-auto-login) with no password required. If set, Langflow requires password authentication.
-
- For more information on configuring OpenRAG with environment variables, see [Environment variables](/reference/configuration).
+ * **Amazon**: Provide your AWS Access Key ID and AWS Secret Access Key with access to your S3 instance. For more information, see the AWS documentation on [Configuring access to AWS applications](https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html).
+ * **Google**: Provide your Google OAuth Client ID and Google OAuth Client Secret. You can generate these in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials). For more information, see the [Google OAuth client documentation](https://developers.google.com/identity/protocols/oauth2).
+ * **Microsoft**: For the Microsoft OAuth Client ID and Microsoft OAuth Client Secret, provide [Azure application registration credentials for SharePoint and OneDrive](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/app-registration?view=odsp-graph-online). For more information, see the [Microsoft Graph OAuth client documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth).
+
+ For more information and variables, see [OpenRAG environment variables](/reference/configuration).
+
+## Start services
+
+1. Start `docling serve` on port 5001 on the host machine:
-5. Start `docling serve` on the host machine.
- OpenRAG Docker installations require that `docling serve` is running on port 5001 on the host machine.
- This enables [Mac MLX](https://opensource.apple.com/projects/mlx/) support for document processing.
-
```bash
uv run python scripts/docling_ctl.py start --port 5001
```
-
-6. Confirm `docling serve` is running.
- ```
+
+ Docling cannot run inside a Docker container due to system-level dependencies, so you must manage it as a separate service on the host machine.
+ For more information, see [Stop, start, and inspect native services](/manage-services#start-native-services).
+
+ This port is required to deploy OpenRAG successfully; don't use a different port.
+ Additionally, this enables the [MLX framework](https://opensource.apple.com/projects/mlx/) for accelerated performance on Apple Silicon Mac machines.
+
+2. Confirm `docling serve` is running.
+
+ ```bash
uv run python scripts/docling_ctl.py status
```
- Make sure the response shows that `docling serve` is running, for example:
+ If `docling serve` is running, the output includes the status, address, and process ID (PID):
+
```bash
Status: running
Endpoint: http://127.0.0.1:5001
@@ -120,239 +113,55 @@ To install OpenRAG with Docker Compose, do the following:
PID: 27746
```
-7. Deploy OpenRAG locally with Docker Compose based on your deployment type.
+3. Deploy the OpenRAG containers locally using the appropriate Docker Compose file for your environment.
+Both files deploy the same services.
-
-
- ```bash
- docker compose build
- docker compose up -d
- ```
-
-
-
- ```bash
- docker compose -f docker-compose-cpu.yml up -d
- ```
-
-
-
+ * [`docker-compose.yml`](https://github.com/langflow-ai/openrag/blob/main/docker-compose.yml): If your host machine has an NVIDIA GPU with CUDA support and compatible NVIDIA drivers, you can use this file to deploy OpenRAG with accelerated processing.
- The OpenRAG Docker Compose file starts five containers:
- | Container Name | Default Address | Purpose |
- |---|---|---|
- | OpenRAG Backend | http://localhost:8000 | FastAPI server and core functionality. |
- | OpenRAG Frontend | http://localhost:3000 | React web interface for users. |
- | Langflow | http://localhost:7860 | AI workflow engine and flow management. |
- | OpenSearch | http://localhost:9200 | Vector database for document storage. |
- | OpenSearch Dashboards | http://localhost:5601 | Database administration interface. |
-
-8. Verify installation by confirming all services are running.
-
- ```bash
- docker compose ps
- ```
-
- You can now access OpenRAG at the following endpoints:
-
- - **Frontend**: http://localhost:3000
- - **Backend API**: http://localhost:8000
- - **Langflow**: http://localhost:7860
-
-9. Continue with [application onboarding](#application-onboarding).
-
-To stop `docling serve` when you're done with your OpenRAG deployment, run:
-
-```bash
-uv run python scripts/docling_ctl.py stop
-```
-
-
-
-## Container management commands
-
-Manage your OpenRAG containers with the following commands.
-These commands are also available in the TUI's [Status menu](/install#status).
-
-### Upgrade containers {#upgrade-containers}
-
-Upgrade your containers to the latest version while preserving your data.
-
-```bash
-docker compose pull
-docker compose up -d --force-recreate
-```
-
-### Reset containers (destructive) {#reset-containers}
-
-:::warning
-These are destructive operations that reset your OpenRAG deployment to an initial state.
-Be aware that data is lost and cannot be recovered after running these commands.
-:::
-
-
-
-
-* Rebuild containers: This command destroys and recreates the containers. Data stored exclusively on the containers is lost, such as Langflow flows.
-The `.env` file, `config` directory, `./openrag-documents` directory, `./opensearch-data` directory, and the `conversations.json` file are preserved.
-
- ```bash
- docker compose up --build --force-recreate --remove-orphans
- ```
-
-* Destroy and recreate containers with the option for additional data removal: These commands destroy the containers, and then recreate them.
-This allows you to delete other OpenRAG data before recreating the containers.
-
- 1. Destroy the containers, volumes, and local images, and then remove (prune) any additional Docker objects:
-
- ```bash
- docker compose down --volumes --remove-orphans --rmi local
- docker system prune -f
- ```
-
- 2. Optional: Remove data that wasn't deleted by the previous commands:
-
- * OpenRAG's `.env` file
- * The contents of OpenRAG's `config` directory
- * The contents of the `./openrag-documents` directory
- * The contents of the `./opensearch-data` directory
- * The `conversations.json` file
-
- 3. Recreate the containers:
-
- ```bash
+ ```bash title="Docker"
+ docker compose build
docker compose up -d
```
-
-
-
-* Rebuild containers: This command destroys and recreates the containers. Data stored exclusively on the containers is lost, such as Langflow flows.
-The `.env` file, `config` directory, `./openrag-documents` directory, `./opensearch-data` directory, and the `conversations.json` file are preserved.
-
- ```bash
- podman-compose up --build --force-recreate --remove-orphans
- ```
-
-* Destroy and recreate containers with the option for additional data removal: These commands destroy the containers, and then recreate them.
-This allows you to delete other OpenRAG data before recreating the containers.
-
- 1. Destroy the containers, volumes, and local images, and then remove (prune) any additional Podman objects:
-
- ```bash
- podman-compose down --volumes --remove-orphans --rmi local
- podman system prune -f
+ ```bash title="Podman"
+ podman compose build
+ podman compose up -d
```
- 2. Optional: Remove data that wasn't deleted by the previous commands:
+ * [`docker-compose-cpu.yml`](https://github.com/langflow-ai/openrag/blob/main/docker-compose-cpu.yml): If your host machine doesn't have NVIDIA GPU support, use this file for a CPU-only OpenRAG deployment.
- * OpenRAG's `.env` file
- * The contents of OpenRAG's `config` directory
- * The contents of the `./openrag-documents` directory
- * The contents of the `./opensearch-data` directory
- * The `conversations.json` file
-
- 3. Recreate the containers:
-
- ```bash
- podman-compose up -d
+ ```bash title="Docker"
+ docker compose -f docker-compose-cpu.yml up -d
```
-
-
+ ```bash title="Podman"
+ podman compose -f docker-compose-cpu.yml up -d
+ ```
-1. Stop all running containers:
+4. Wait for the OpenRAG containers to start, and then confirm that all containers are running:
- ```bash
- docker stop $(docker ps -q)
+ ```bash title="Docker"
+ docker compose ps
```
-2. Remove all containers, including stopped containers:
-
- ```bash
- docker rm --force $(docker ps -aq)
+ ```bash title="Podman"
+ podman compose ps
```
-3. Remove all images:
+ The OpenRAG Docker Compose files deploy the following containers:
- ```bash
- docker rmi --force $(docker images -q)
- ```
+ | Container Name | Default address | Purpose |
+ |---|---|---|
+ | OpenRAG Backend | http://localhost:8000 | FastAPI server and core functionality. |
+ | OpenRAG Frontend | http://localhost:3000 | React web interface for user interaction. |
+ | Langflow | http://localhost:7860 | [AI workflow engine](/agents). |
+ | OpenSearch | http://localhost:9200 | Datastore for [knowledge](/knowledge). |
+ | OpenSearch Dashboards | http://localhost:5601 | OpenSearch database administration interface. |
-4. Remove all volumes:
+ When the containers are running, you can access your OpenRAG services at their addresses.
- ```bash
- docker volume prune --force
- ```
+5. Access the OpenRAG frontend at `http://localhost:3000`, and then continue with the [application onboarding process](#application-onboarding).
-5. Remove all networks except the default network:
+
- ```bash
- docker network prune --force
- ```
-
-6. Clean up any leftover data:
-
- ```bash
- docker system prune --all --force --volumes
- ```
-
-7. Optional: Remove data that wasn't deleted by the previous commands:
-
- * OpenRAG's `.env` file
- * The contents of OpenRAG's `config` directory
- * The contents of the `./openrag-documents` directory
- * The contents of the `./opensearch-data` directory
- * The `conversations.json` file
-
-
-
-
-1. Stop all running containers:
-
- ```bash
- podman stop --all
- ```
-
-2. Remove all containers, including stopped containers:
-
- ```bash
- podman rm --all --force
- ```
-
-3. Remove all images:
-
- ```bash
- podman rmi --all --force
- ```
-
-4. Remove all volumes:
-
- ```bash
- podman volume prune --force
- ```
-
-5. Remove all networks except the default network:
-
- ```bash
- podman network prune --force
- ```
-
-6. Clean up any leftover data:
-
- ```bash
- podman system prune --all --force --volumes
- ```
-
-7. Optional: Remove data that wasn't deleted by the previous commands:
-
- * OpenRAG's `.env` file
- * The contents of OpenRAG's `config` directory
- * The contents of the `./openrag-documents` directory
- * The contents of the `./opensearch-data` directory
- * The `conversations.json` file
-
-
-
-
-After resetting your containers, you must repeat [application onboarding](#application-onboarding).
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/docs/get-started/install-options.mdx b/docs/docs/get-started/install-options.mdx
new file mode 100644
index 00000000..90f800a5
--- /dev/null
+++ b/docs/docs/get-started/install-options.mdx
@@ -0,0 +1,34 @@
+---
+title: Select an installation method
+slug: /install-options
+---
+
+The [OpenRAG architecture](/#openrag-architecture) is lightweight and container-based with a central OpenRAG backend that orchestrates the various services and external connectors.
+Depending on your use case, OpenRAG can assist with service management, or you can manage the services yourself.
+
+Select the installation method that best fits your needs:
+
+* **Use the [Terminal User Interface (TUI)](/tui) to manage services**: For guided configuration and simplified service management, install OpenRAG with TUI-managed services. Use one of the following options:
+
+ * [**Automatic installer script**](/install): Run one script to install the required dependencies and OpenRAG.
+ * [**`uv`**](/install-uv): Install OpenRAG as a dependency of a new or existing Python project.
+ * [**`uvx`**](/install-uvx): Install OpenRAG without creating a project or modifying your project's dependencies.
+
+* [**Install OpenRAG on Microsoft Windows**](/install-windows): On Windows machines, you must install OpenRAG within the Windows Subsystem for Linux (WSL).
+
+ :::warning
+ OpenRAG doesn't support nested virtualization; don't run OpenRAG on a WSL distribution that is inside a Windows VM.
+ :::
+
+* [**Manage your own services**](/docker): You can use Docker or Podman to deploy self-managed OpenRAG services.
+
+The first time you start OpenRAG, you must complete the application onboarding process.
+This is required for all installation methods because it prepares the minimum required configuration for OpenRAG to run.
+For TUI-managed services, you must also complete initial setup before you start the OpenRAG services.
+For more information, see the instructions for your preferred installation method.
+
+Your OpenRAG configuration is stored in a `.env` file in the OpenRAG installation directory.
+When using TUI-managed services, this file is created automatically, or you can provide a pre-populated `.env` file before starting the TUI.
+The TUI prompts you for the required values during setup and onboarding, and any values detected in a preexisting `.env` file are populated automatically.
+When using self-managed services, you must provide a pre-populated `.env` file, as you would for any Docker or Podman deployment.
+For more information, see the instructions for your preferred installation method and the [OpenRAG environment variables reference](/reference/configuration).
\ No newline at end of file
diff --git a/docs/docs/get-started/install-uv.mdx b/docs/docs/get-started/install-uv.mdx
new file mode 100644
index 00000000..9a73546e
--- /dev/null
+++ b/docs/docs/get-started/install-uv.mdx
@@ -0,0 +1,123 @@
+---
+title: Install OpenRAG in a Python project with uv
+slug: /install-uv
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import PartialOnboarding from '@site/docs/_partial-onboarding.mdx';
+import PartialSetup from '@site/docs/_partial-setup.mdx';
+import PartialPrereqCommon from '@site/docs/_partial-prereq-common.mdx';
+import PartialPrereqNoScript from '@site/docs/_partial-prereq-no-script.mdx';
+import PartialPrereqWindows from '@site/docs/_partial-prereq-windows.mdx';
+import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx';
+import PartialInstallNextSteps from '@site/docs/_partial-install-next-steps.mdx';
+import PartialOpenSearchAuthMode from '@site/docs/_partial-opensearch-auth-mode.mdx';
+
+Use [`uv`](https://docs.astral.sh/uv/getting-started/installation/) to install OpenRAG as a managed or unmanaged dependency in a new or existing Python project.
+
+When you install OpenRAG with `uv`, you will use the [Terminal User Interface (TUI)](/tui) to configure and manage your OpenRAG deployment.
+
+For other installation methods, see [Select an installation method](/install-options).
+
+## Prerequisites
+
+
+
+
+
+
+
+
+
+## Install and start OpenRAG with uv
+
+There are two ways to install OpenRAG with `uv`:
+
+* [**`uv add`** (Recommended)](#uv-add): Install OpenRAG as a managed dependency in a new or existing `uv` Python project.
+This is recommended because it adds OpenRAG to your `pyproject.toml` and lockfile for better management of dependencies and the virtual environment.
+
+* [**`uv pip install`**](#uv-pip-install): Use the [`uv pip` interface](https://docs.astral.sh/uv/pip/) to install OpenRAG into an existing Python project that uses `pip`, `pip-tools`, and `virtualenv` commands.
+
+If you encounter errors during installation, see [Troubleshoot OpenRAG](/support/troubleshoot).
+
+### Use uv add {#uv-add}
+
+1. Create a new `uv`-managed Python project:
+
+ ```bash
+ uv init PROJECT_NAME
+ ```
+
+2. Change into your new project directory:
+
+ ```bash
+ cd PROJECT_NAME
+ ```
+
+ Because `uv` manages the virtual environment for you, you won't see a `(venv)` prompt.
+ `uv` commands automatically use the project's virtual environment.
+
+3. Add OpenRAG to your project:
+
+ * Add the latest version:
+
+ ```bash
+ uv add openrag
+ ```
+
+ * Add a specific version:
+
+ ```bash
+ uv add openrag==0.1.30
+ ```
+
+ * Add a local wheel:
+
+ ```bash
+ uv add path/to/openrag-VERSION-py3-none-any.whl
+ ```
+
+ For more options, see [Managing dependencies with `uv`](https://docs.astral.sh/uv/concepts/projects/dependencies/).
+
+4. Optional: If you want to use a pre-populated [OpenRAG `.env` file](/reference/configuration), copy it to this directory before starting OpenRAG.
+
+5. Start the OpenRAG TUI:
+
+ ```bash
+ uv run openrag
+ ```
+
+### Use uv pip install {#uv-pip-install}
+
+1. Activate your virtual environment.
+
+2. Install the OpenRAG Python package:
+
+ ```bash
+ uv pip install openrag
+ ```
+
+3. Optional: If you want to use a pre-populated [OpenRAG `.env` file](/reference/configuration), copy it to this directory before starting OpenRAG.
+
+4. Start the OpenRAG TUI:
+
+ ```bash
+ uv run openrag
+ ```
+
+## Set up OpenRAG with the TUI {#setup}
+
+When you install OpenRAG with `uv`, you manage the OpenRAG services with the TUI.
+The TUI guides you through the initial configuration process before you start the OpenRAG services.
+
+Your configuration values are stored in an [OpenRAG `.env` file](/reference/configuration) that is created automatically in the Python project where you installed OpenRAG.
+If OpenRAG detects an existing `.env` file in this directory, then the TUI can populate those values automatically during setup and onboarding.
+
+Container definitions are stored in the `docker-compose` files in the same directory as the OpenRAG `.env` file.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/get-started/install-uvx.mdx b/docs/docs/get-started/install-uvx.mdx
new file mode 100644
index 00000000..a165191f
--- /dev/null
+++ b/docs/docs/get-started/install-uvx.mdx
@@ -0,0 +1,82 @@
+---
+title: Invoke OpenRAG with uvx
+slug: /install-uvx
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import PartialOnboarding from '@site/docs/_partial-onboarding.mdx';
+import PartialSetup from '@site/docs/_partial-setup.mdx';
+import PartialPrereqCommon from '@site/docs/_partial-prereq-common.mdx';
+import PartialPrereqNoScript from '@site/docs/_partial-prereq-no-script.mdx';
+import PartialPrereqWindows from '@site/docs/_partial-prereq-windows.mdx';
+import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx';
+import PartialInstallNextSteps from '@site/docs/_partial-install-next-steps.mdx';
+import PartialOpenSearchAuthMode from '@site/docs/_partial-opensearch-auth-mode.mdx';
+
+Use [`uvx`](https://docs.astral.sh/uv/guides/tools/#running-tools) to invoke OpenRAG outside of a Python project or without modifying your project's dependencies.
+
+:::tip
+The [automatic installer script](/install) also uses `uvx` to install OpenRAG.
+:::
+
+When you install OpenRAG with `uvx`, you will use the [Terminal User Interface (TUI)](/tui) to configure and manage your OpenRAG deployment.
+
+This installation method is best for testing OpenRAG by running it outside of a Python project.
+For other installation methods, see [Select an installation method](/install-options).
+
+## Prerequisites
+
+
+
+
+
+
+
+
+
+## Install and run OpenRAG with uvx
+
+1. Create a directory to store your OpenRAG configuration files and data, and then change to that directory:
+
+ ```bash
+ mkdir openrag-workspace
+ cd openrag-workspace
+ ```
+
+2. Optional: If you want to use a pre-populated [OpenRAG `.env` file](/reference/configuration), copy it to this directory before invoking OpenRAG.
+
+3. Invoke OpenRAG:
+
+ ```bash
+ uvx openrag
+ ```
+
+ You can invoke a specific version using any of the [`uvx` version specifiers](https://docs.astral.sh/uv/guides/tools/#requesting-specific-versions), such as `--from`:
+
+ ```bash
+ uvx --from openrag==0.1.30 openrag
+ ```
+
+ Invoking OpenRAG with `uvx openrag` creates a cached, ephemeral environment for the TUI in your local `uv` cache.
+ By invoking OpenRAG in a specific directory, your OpenRAG configuration files and data are stored separately from the `uv` cache.
+ Clearing the `uv` cache doesn't remove your entire OpenRAG installation.
+ After clearing the cache, you can re-invoke OpenRAG (`uvx openrag`) to restart the TUI with your preserved configuration and data.
+
+If you encounter errors during installation, see [Troubleshoot OpenRAG](/support/troubleshoot).
+
+## Set up OpenRAG with the TUI {#setup}
+
+When you install OpenRAG with `uvx`, you manage the OpenRAG services with the TUI.
+The TUI guides you through the initial configuration process before you start the OpenRAG services.
+
+Your configuration values are stored in an [OpenRAG `.env` file](/reference/configuration) that is created automatically in the OpenRAG installation directory, which is the directory where you invoked OpenRAG.
+If OpenRAG detects an existing `.env` file in this directory, then the TUI can populate those values automatically during setup and onboarding.
+
+Container definitions are stored in the `docker-compose` files in the same directory as the OpenRAG `.env` file.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/docs/_partial-wsl-install.mdx b/docs/docs/get-started/install-windows.mdx
similarity index 65%
rename from docs/docs/_partial-wsl-install.mdx
rename to docs/docs/get-started/install-windows.mdx
index 4db6d1dd..664f8702 100644
--- a/docs/docs/_partial-wsl-install.mdx
+++ b/docs/docs/get-started/install-windows.mdx
@@ -1,4 +1,21 @@
-1. [Install WSL](https://learn.microsoft.com/en-us/windows/wsl/install) with the Ubuntu distribution using WSL 2:
+---
+title: Install OpenRAG on Microsoft Windows
+slug: /install-windows
+---
+
+If you're using Windows, you must install OpenRAG within the Windows Subsystem for Linux (WSL).
+
+:::warning
+Nested virtualization isn't supported.
+
+OpenRAG isn't compatible with nested virtualization, which can cause networking issues.
+Don't install OpenRAG on a WSL distribution that is installed inside a Windows VM.
+Instead, install OpenRAG on your base OS or a non-nested Linux VM.
+:::
+
+## Install OpenRAG in the WSL
+
+1. [Install WSL](https://learn.microsoft.com/en-us/windows/wsl/install) with an Ubuntu distribution using WSL 2:
```powershell
wsl --install -d Ubuntu
@@ -8,18 +25,18 @@
For existing WSL installations, you can [change the distribution](https://learn.microsoft.com/en-us/windows/wsl/install#change-the-default-linux-distribution-installed) and [check the WSL version](https://learn.microsoft.com/en-us/windows/wsl/install#upgrade-version-from-wsl-1-to-wsl-2).
- :::warning Known limitation
- OpenRAG isn't compatible with nested virtualization, which can cause networking issues.
- Don't install OpenRAG on a WSL distribution that is installed inside a Windows VM.
- Instead, install OpenRAG on your base OS or a non-nested Linux VM.
- :::
-
2. [Start your WSL Ubuntu distribution](https://learn.microsoft.com/en-us/windows/wsl/install#ways-to-run-multiple-linux-distributions-with-wsl) if it doesn't start automatically.
3. [Set up a username and password for your WSL distribution](https://learn.microsoft.com/en-us/windows/wsl/setup/environment#set-up-your-linux-username-and-password).
4. [Install Docker Desktop for Windows with WSL 2](https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers). When you reach the Docker Desktop **WSL integration** settings, make sure your Ubuntu distribution is enabled, and then click **Apply & Restart** to enable Docker support in WSL.
+ The Docker Desktop WSL integration makes Docker available within your WSL distribution.
+ You don't need to install Docker or Podman separately in your WSL distribution before you install OpenRAG.
+
5. Install and run OpenRAG from within your WSL Ubuntu distribution.
-
+You can install OpenRAG in your WSL distribution using any of the [OpenRAG installation methods](/install-options).
+
+## Troubleshoot OpenRAG in WSL
+
If you encounter issues with port forwarding or the Windows Firewall, you might need to adjust the [Hyper-V firewall settings](https://learn.microsoft.com/en-us/windows/security/operating-system-security/network-security/windows-firewall/hyper-v-firewall) to allow communication between your WSL distribution and the Windows host. For more troubleshooting advice for networking issues, see [Troubleshooting WSL common issues](https://learn.microsoft.com/en-us/windows/wsl/troubleshooting#common-issues).
\ No newline at end of file
diff --git a/docs/docs/get-started/install.mdx b/docs/docs/get-started/install.mdx
index 789f12c8..d044e48e 100644
--- a/docs/docs/get-started/install.mdx
+++ b/docs/docs/get-started/install.mdx
@@ -1,469 +1,81 @@
---
-title: Install OpenRAG with TUI
+title: Install OpenRAG with the automatic installer script
slug: /install
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialOnboarding from '@site/docs/_partial-onboarding.mdx';
-import PartialWsl from '@site/docs/_partial-wsl-install.mdx';
+import PartialSetup from '@site/docs/_partial-setup.mdx';
+import PartialPrereqCommon from '@site/docs/_partial-prereq-common.mdx';
+import PartialPrereqWindows from '@site/docs/_partial-prereq-windows.mdx';
+import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx';
+import PartialInstallNextSteps from '@site/docs/_partial-install-next-steps.mdx';
+import PartialOpenSearchAuthMode from '@site/docs/_partial-opensearch-auth-mode.mdx';
-[Install OpenRAG](#install) and then run the [OpenRAG Terminal User Interface(TUI)](#setup) to start your OpenRAG deployment with a guided setup process.
+:::tip
+To quickly install and test OpenRAG's core features, try the [quickstart](/quickstart).
+:::
-The OpenRAG Terminal User Interface (TUI) allows you to set up, configure, and monitor your OpenRAG deployment directly from the terminal.
+The installer script installs `uv`, Docker or Podman, Docker Compose, and OpenRAG.
+Then, it installs and runs OpenRAG with `uvx`.
-
+When you install OpenRAG with the installer script, you will use the [Terminal User Interface (TUI)](/tui) to configure and manage your OpenRAG deployment.
-Instead of starting OpenRAG using Docker commands and manually editing values in the `.env` file, the TUI walks you through the setup. It prompts for variables where required, creates a `.env` file for you, and then starts OpenRAG.
-
-Once OpenRAG is running, use the TUI to monitor your application, control your containers, and retrieve logs.
-
-If you prefer running Podman or Docker containers and manually editing `.env` files, see [Install OpenRAG Containers](/docker).
+This installation method is best for testing OpenRAG by running it outside of a Python project.
+For other installation methods, see [Select an installation method](/install-options).
## Prerequisites
-- All OpenRAG installations require [Python](https://www.python.org/downloads/release/python-3100/) version 3.13 or later.
+
-- If you aren't using the automatic installer script, install the following:
+
- - [uv](https://docs.astral.sh/uv/getting-started/installation/).
- - [Podman](https://podman.io/docs/installation) (recommended) or [Docker](https://docs.docker.com/get-docker/).
- - [`podman-compose`](https://docs.podman.io/en/latest/markdown/podman-compose.1.html) or [Docker Compose](https://docs.docker.com/compose/install/). To use Docker Compose with Podman, you must alias Docker Compose commands to Podman commands.
+
-- Microsoft Windows only: To run OpenRAG on Windows, you must use the Windows Subsystem for Linux (WSL).
+## Run the installer script {#install}
-
- Install WSL for OpenRAG
+1. Create a directory to store your OpenRAG configuration files and data, and then change to that directory:
-
+ ```bash
+ mkdir openrag-workspace
+ cd openrag-workspace
+ ```
-
+2. Get and run the installer script:
-- Prepare model providers and credentials.
+ ```bash
+ curl -fsSL https://docs.openr.ag/files/run_openrag_with_prereqs.sh | bash
+ ```
- During [application onboarding](#application-onboarding), you must select language model and embedding model providers.
- If your chosen provider offers both types, you can use the same provider for both selections.
- If your provider offers only one type, such as Anthropic, you must select two providers.
+ The installer script installs OpenRAG with [`uvx`](https://docs.astral.sh/uv/guides/tools/#running-tools) in the directory where you run the script.
- Gather the credentials and connection details for your chosen model providers before starting onboarding:
+3. Wait while the installer script prepares your environment and installs OpenRAG.
+You might be prompted to install certain dependencies if they aren't already present in your environment.
- - OpenAI: Create an [OpenAI API key](https://platform.openai.com/api-keys).
- - Anthropic language models: Create an [Anthropic API key](https://www.anthropic.com/docs/api/reference).
- - IBM watsonx.ai: Get your watsonx.ai API endpoint, IBM project ID, and IBM API key from your watsonx deployment.
- - Ollama: Use the [Ollama documentation](https://docs.ollama.com/) to set up your Ollama instance locally, in the cloud, or on a remote server, and then get your Ollama server's base URL.
+The entire process can take a few minutes.
+Once the environment is ready, the OpenRAG TUI starts.
-- Optional: Install GPU support with an NVIDIA GPU, [CUDA](https://docs.nvidia.com/cuda/) support, and compatible NVIDIA drivers on the OpenRAG host machine. If you don't have GPU capabilities, OpenRAG provides an alternate CPU-only deployment.
+
-## Install OpenRAG {#install}
-
-Choose an installation method based on your needs:
-
-* For new users, the automatic installer script detects and installs prerequisites and then runs OpenRAG.
-* For a quick test, use `uvx` to run OpenRAG without creating a project or modifying files.
-* Use `uv add` to install OpenRAG as a managed dependency in a new or existing Python project.
-* Use `uv pip install` to install OpenRAG into an existing virtual environment.
-
-
-
-
- The script detects and installs uv, Docker/Podman, and Docker Compose prerequisites, then runs OpenRAG with `uvx`.
-
- 1. Create a directory to store the OpenRAG configuration files:
- ```bash
- mkdir openrag-workspace
- cd openrag-workspace
- ```
-
- 2. Run the installer:
- ```bash
- curl -fsSL https://docs.openr.ag/files/run_openrag_with_prereqs.sh | bash
- ```
-
- The TUI creates a `.env` file and docker-compose files in the current working directory.
-
-
-
-
- Use `uvx` to quickly run OpenRAG without creating a project or modifying any files.
-
- 1. Create a directory to store the OpenRAG configuration files:
- ```bash
- mkdir openrag-workspace
- cd openrag-workspace
- ```
-
- 2. Run OpenRAG:
- ```bash
- uvx openrag
- ```
-
- To run a specific version:
- ```bash
- uvx --from openrag==0.1.30 openrag
- ```
-
- The TUI creates a `.env` file and docker-compose files in the current working directory.
-
-
-
-
- Use `uv add` to install OpenRAG as a dependency in your Python project. This adds OpenRAG to your `pyproject.toml` and lockfile, making your installation reproducible and version-controlled.
-
- 1. Create a new project with a virtual environment:
- ```bash
- uv init YOUR_PROJECT_NAME
- cd YOUR_PROJECT_NAME
- ```
-
- The `(venv)` prompt doesn't change, but `uv` commands will automatically use the project's virtual environment.
-
- 2. Add OpenRAG to your project:
- ```bash
- uv add openrag
- ```
-
- To add a specific version:
- ```bash
- uv add openrag==0.1.30
- ```
-
- 3. Start the OpenRAG TUI:
- ```bash
- uv run openrag
- ```
-
-
- Install a local wheel
-
- If you downloaded the OpenRAG wheel to your local machine, install it by specifying its path:
-
- 1. Add the wheel to your project:
- ```bash
- uv add PATH/TO/openrag-VERSION-py3-none-any.whl
- ```
-
- Replace `PATH/TO/` and `VERSION` with the path and version of your downloaded OpenRAG `.whl` file.
-
- 2. Run OpenRAG:
- ```bash
- uv run openrag
- ```
-
-
-
-
-
- Use `uv pip install` to install OpenRAG into an existing virtual environment that isn't managed by `uv`.
-
- :::tip
- For new projects, `uv add` is recommended as it manages dependencies in your project's lockfile.
- :::
-
- 1. Activate your virtual environment.
-
- 2. Install OpenRAG:
- ```bash
- uv pip install openrag
- ```
-
- 3. Run OpenRAG:
- ```bash
- uv run openrag
- ```
-
-
-
-
-Continue with [Set up OpenRAG with the TUI](#setup).
+Because the installer script uses `uvx`, it creates a cached, ephemeral environment in your local `uv` cache, and your OpenRAG configuration files and data are stored separately from the `uv` cache.
+Clearing the cache doesn't delete your entire OpenRAG installation, only the temporary TUI environment.
+After clearing the cache, run `uvx openrag` to [access the TUI](/tui) and continue with your preserved configuration and data.
If you encounter errors during installation, see [Troubleshoot OpenRAG](/support/troubleshoot).
## Set up OpenRAG with the TUI {#setup}
-The OpenRAG setup process creates a `.env` file at the root of your OpenRAG directory, and then starts OpenRAG.
-If it detects a `.env` file in the OpenRAG root directory, it sources any variables from the `.env` file.
+When you install OpenRAG with the installer script, you manage the OpenRAG services with the TUI.
+The TUI guides you through the initial configuration process before you start the OpenRAG services.
-The TUI offers two setup methods to populate the required values. **Basic Setup** can generate all minimum required values for OpenRAG. However, **Basic Setup** doesn't enable [OAuth connectors for cloud storage](/knowledge#auth). If you want to use OAuth connectors to upload documents from cloud storage, select **Advanced Setup**.
-If OpenRAG detects OAuth credentials, it recommends **Advanced Setup**.
+Your configuration values are stored in an [OpenRAG `.env` file](/reference/configuration) that is created automatically in the OpenRAG installation directory, which is the directory where you ran the installer script.
+If OpenRAG detects an existing `.env` file in this directory, then the TUI can populate those values automatically during setup and onboarding.
-
-
+Container definitions are stored in the `docker-compose` files in the same directory as the OpenRAG `.env` file.
- 1. To install OpenRAG with **Basic Setup**, click **Basic Setup** or press 1.
- 2. Click **Generate Passwords** to generate passwords for OpenSearch and Langflow.
-
- The OpenSearch password is required. The Langflow admin password is optional.
- If no Langflow admin password is generated, Langflow runs in [autologin mode](https://docs.langflow.org/api-keys-and-authentication#langflow-auto-login) with no password required.
-
- 3. Optional: Paste your OpenAI API key in the OpenAI API key field. You can also provide this during onboarding or choose a different model provider.
- 4. Click **Save Configuration**.
- Your passwords are saved in the `.env` file used to start OpenRAG.
- 5. To start OpenRAG, click **Start All Services**.
- Startup pulls container images and runs them, so it can take some time.
- When startup is complete, the TUI displays the following:
- ```bash
- Services started successfully
- Command completed successfully
- ```
- 6. To start the Docling service, under **Native Services**, click **Start**.
- 7. To open the OpenRAG application, navigate to the TUI main menu, and then click **Open App**.
- Alternatively, in your browser, navigate to `localhost:3000`.
- 8. Continue with [application onboarding](#application-onboarding).
-
-
-
- 1. To install OpenRAG with **Advanced Setup**, click **Advanced Setup** or press 2.
- 2. Click **Generate Passwords** to generate passwords for OpenSearch and Langflow.
-
- The OpenSearch password is required. The Langflow admin password is optional.
- If no Langflow admin password is generated, Langflow runs in [autologin mode](https://docs.langflow.org/api-keys-and-authentication#langflow-auto-login) with no password required.
-
- 3. Paste your OpenAI API key in the OpenAI API key field.
- 4. If you want to upload documents from external storage, such as Google Drive, add the required OAuth credentials for the connectors that you want to use. These settings can be populated automatically if OpenRAG detects these credentials in a `.env` file in the OpenRAG installation directory.
-
- * **Amazon**: Provide your AWS Access Key ID and AWS Secret Access Key with access to your S3 instance. For more information, see the AWS documentation on [Configuring access to AWS applications](https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html).
- * **Google**: Provide your Google OAuth Client ID and Google OAuth Client Secret. You can generate these in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials). For more information, see the [Google OAuth client documentation](https://developers.google.com/identity/protocols/oauth2).
- * **Microsoft**: For the Microsoft OAuth Client ID and Microsoft OAuth Client Secret, provide [Azure application registration credentials for SharePoint and OneDrive](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/app-registration?view=odsp-graph-online). For more information, see the [Microsoft Graph OAuth client documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth).
-
- You can [manage OAuth credentials](/ingestion#oauth-ingestion) later, but it is recommended to configure them during initial set up.
-
- 5. The OpenRAG TUI presents redirect URIs for your OAuth app.
- These are the URLs your OAuth provider will redirect back to after user sign-in.
- Register these redirect values with your OAuth provider as they are presented in the TUI.
- 6. Click **Save Configuration**.
- 7. To start OpenRAG, click **Start All Services**.
- Startup pulls container images and runs them, so it can take some time.
- When startup is complete, the TUI displays the following:
- ```bash
- Services started successfully
- Command completed successfully
- ```
- 8. To start the Docling service, under **Native Services**, click **Start**.
- 9. To open the OpenRAG application, navigate to the TUI main menu, and then click **Open App**.
- Alternatively, in your browser, navigate to `localhost:3000`.
-
- 10. If you enabled OAuth connectors, you must sign in to your OAuth provider before being redirected to your OpenRAG instance.
-
- 11. Two additional variables are available for **Advanced Setup** at this point.
- Only change these variables if you have a non-default network configuration for your deployment, such as using a reverse proxy or custom domain.
-
- * `LANGFLOW_PUBLIC_URL`: Sets the base address to access the Langflow web interface. This is where users interact with flows in a browser.
-
- * `WEBHOOK_BASE_URL`: Sets the base address of the OpenRAG OAuth connector endpoint.
- Supported webhook endpoints:
-
- - Amazon S3: Not applicable.
- - Google Drive: `/connectors/google_drive/webhook`
- - OneDrive: `/connectors/onedrive/webhook`
- - SharePoint: `/connectors/sharepoint/webhook`
-
- 12. Continue with [application onboarding](#application-onboarding).
-
-
+
-## Exit the OpenRAG TUI
-
-To exit the OpenRAG TUI, navigate to the main menu, and then press q.
-The OpenRAG containers continue to run until they are stopped.
-For more information, see [Manage OpenRAG containers with the TUI ](#tui-container-management).
-
-To relaunch the TUI, run `uv run openrag`.
-If you installed OpenRAG with `uvx`, run `uvx openrag`.
-
-## Manage OpenRAG containers with the TUI {#tui-container-management}
-
-After installation, the TUI can deploy, manage, and upgrade your OpenRAG containers.
-
-### Diagnostics
-
-The **Diagnostics** menu provides health monitoring for your container runtimes and monitoring of your OpenSearch security.
-
-### Status {#status}
-
-The **Status** menu displays information on your container deployment.
-Here you can check container health, find your service ports, view logs, and upgrade your containers.
-
-* **Logs**: To view streaming logs, select the container you want to view, and press l.
-To copy the logs, click **Copy to Clipboard**.
-
-* **Upgrade**: Check for updates. For more information, see [upgrade OpenRAG](#upgrade).
-
-* **Factory Reset**: This is a destructive action that [resets your containers](#reset-containers).
-
-* **Native services**: [View and manage OpenRAG services](#start-all-services) that run directly on your local machine instead of a container.
-
-### Reset containers {#reset-containers}
-
-Reset your OpenRAG deployment by recreating the containers and removing some related data.
-
-:::warning
-This is a destructive action that destroys the following:
-
-* All OpenRAG containers, volumes, and local images
-* Any additional Docker objects
-* The contents of OpenRAG's `config` and `./opensearch-data` directories
-* The `conversations.json` file
-
-This operation _doesn't_ remove the `.env` file or the contents of the `./openrag-documents` directory.
-:::
-
-1. To destroy and recreate your OpenRAG containers, go to the TUI [**Status** menu](#status), and then click **Factory Reset**.
-
- This function runs the following commands _and_ deletes the contents of OpenRAG's `config` and `./opensearch-data` directories.
-
- ```bash
- docker compose down --volumes --remove-orphans --rmi local
- docker system prune -f
- ```
-
-2. If you reset your containers as part of reinstalling OpenRAG, continue the [reinstallation process](#reinstall) after resetting the containers.
-Otherwise, in the TUI **Setup** menu, repeat the [setup process](#setup) to start the services and launch the OpenRAG app. Your OpenRAG passwords, OAuth credentials (if previously set), and onboarding configuration are restored from the `.env` file.
-
-### Start all services {#start-all-services}
-
-Through the TUI, you can view and manage OpenRAG services that run in containers and directly on your local machine.
-
-#### Start containers
-
-On the TUI main page or the **Setup** menu, click **Start All Services** to start the OpenRAG containers and launch OpenRAG itself.
-
-When you start all services, the following processes happen:
-
-1. OpenRAG automatically detects your container runtime, and then checks if your machine has compatible GPU support by checking for `CUDA`, `NVIDIA_SMI`, and Docker/Podman runtime support. This check determines which Docker Compose file OpenRAG uses.
-
-2. OpenRAG pulls the OpenRAG container images with `docker compose pull` if any images are missing.
-
-3. OpenRAG deploys the containers with `docker compose up -d`.
-
-#### Start native services (Docling)
-
-A _native service_ in OpenRAG is a service that runs locally on your machine, not within a container. For example, the `docling serve` process is an OpenRAG native service because this document processing service runs on your local machine, separate from the OpenRAG containers.
-
-From the **Status** menu, you can view the status, port, and process ID (PID) of the OpenRAG native services.
-You can also click **Stop** or **Restart** to stop and start OpenRAG native services.
-
-## Upgrade OpenRAG {#upgrade}
-
-To upgrade OpenRAG, upgrade the OpenRAG Python package, and then upgrade the OpenRAG containers.
-
-This is a two part process because upgrading the OpenRAG Python package updates the TUI and Python code, but the container versions are controlled by environment variables in your `.env` file.
-
-1. Stop your OpenRAG containers: In the OpenRAG TUI, go to the **Status** menu, and then click **Stop Services**.
-
-2. Upgrade the OpenRAG Python package to the latest version from [PyPI](https://pypi.org/project/openrag/).
-
-
-
-
- Use these steps to upgrade the Python package if you installed OpenRAG using the automatic installer or `uvx`:
-
- 1. Navigate to your OpenRAG workspace directory:
-
- ```bash
- cd openrag-workspace
- ```
-
- 2. Upgrade the OpenRAG package:
-
- ```bash
- uvx --from openrag openrag
- ```
-
- To upgrade to a specific version:
-
- ```bash
- uvx --from openrag==0.1.33 openrag
- ```
-
-
-
-
- Use these steps to upgrade the Python package if you installed OpenRAG in a Python project with `uv add`:
-
- 1. Navigate to your project directory:
-
- ```bash
- cd YOUR_PROJECT_NAME
- ```
-
- 2. Update OpenRAG to the latest version:
-
- ```bash
- uv add --upgrade openrag
- ```
-
- To upgrade to a specific version:
-
- ```bash
- uv add --upgrade openrag==0.1.33
- ```
-
- 3. Start the OpenRAG TUI:
-
- ```bash
- uv run openrag
- ```
-
-
-
-
- Use these steps to upgrade the Python package if you installed OpenRAG in a venv with `uv pip install`:
-
- 1. Activate your virtual environment.
-
- 2. Upgrade OpenRAG:
-
- ```bash
- uv pip install --upgrade openrag
- ```
-
- To upgrade to a specific version:
-
- ```bash
- uv pip install --upgrade openrag==0.1.33
- ```
-
- 3. Start the OpenRAG TUI:
-
- ```bash
- uv run openrag
- ```
-
-
-
-
-3. Start the upgraded OpenRAG containers: In the OpenRAG TUI, click **Start All Services**, and then wait while the containers start.
-
- After upgrading the Python package, OpenRAG runs `docker compose pull` to get the appropriate container images matching the version specified in your OpenRAG `.env` file. Then, it recreates the containers with the new images using `docker compose up -d --force-recreate`.
-
- In the `.env` file, the `OPENRAG_VERSION` [environment variable](/reference/configuration#system-settings) is set to `latest` by default, which it pulls the `latest` available container images.
- To pin a specific container image version, you can set `OPENRAG_VERSION` to the desired container image version, such as `OPENRAG_VERSION=0.1.33`.
-
- However, when you upgrade the Python package, OpenRAG automatically attempts to keep the `OPENRAG_VERSION` synchronized with the Python package version.
- You might need to edit the `.env` file after upgrading the Python package to enforce a different container version.
- The TUI warns you if it detects a version mismatch.
-
- If you get an error that `langflow container already exists` error during upgrade, see [Langflow container already exists during upgrade](/support/troubleshoot#langflow-container-already-exists-during-upgrade).
-
-4. When the upgrade process is complete, you can close the **Status** window and continue using OpenRAG.
-
-## Reinstall OpenRAG {#reinstall}
-
-Reset your OpenRAG deployment by recreating the containers and, optionally, removing related data:
-
-1. In the TUI, [reset your containers](#reset-containers) to destroy the following:
-
- * All existing OpenRAG containers, volumes, and local images
- * Any additional Docker objects
- * The contents of OpenRAG's `config` and `./opensearch-data` directories
- * The `conversations.json` file
-
-2. Optional: Remove data that wasn't deleted by the **Factory Reset** operation. For a completely fresh installation, delete all of this data.
-
- * **OpenRAG's `.env` file**: Contains your OpenRAG configuration, including OpenRAG passwords, API keys, OAuth settings, and other [environment variables](/reference/configuration). If you delete this file, you must either repeat the [setup process](#setup) to create a new `.env` file, or add a populated `.env` file to your OpenRAG installation directory before restarting OpenRAG.
- * **The contents of the `./openrag-documents` directory**: Contains documents that you uploaded to OpenRAG. Delete these files to prevent documents from being reingested to your knowledge base after restarting OpenRAG. However, you might want to preserve OpenRAG's [default documents](https://github.com/langflow-ai/openrag/tree/main/openrag-documents).
-
-3. In the TUI **Setup** menu, repeat the [setup process](#setup) to configure OpenRAG, restart the services, and launch the OpenRAG app, and repeat [application onboarding](#application-onboarding).
-If OpenRAG detects a `.env` file, it automatically populates any OpenRAG passwords, OAuth credentials, and onboarding configuration set in that file.
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/docs/get-started/manage-services.mdx b/docs/docs/get-started/manage-services.mdx
new file mode 100644
index 00000000..4ba0cc1d
--- /dev/null
+++ b/docs/docs/get-started/manage-services.mdx
@@ -0,0 +1,187 @@
+---
+title: Manage OpenRAG containers and services
+slug: /manage-services
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import PartialDockerComposeUp from '@site/docs/_partial-docker-compose-up.mdx';
+import PartialDockerComposeDownAndPrune from '@site/docs/_partial-docker-compose-down-and-prune.mdx';
+import PartialFactorResetWarning from '@site/docs/_partial-factory-reset-warning.mdx';
+
+Service management is an essential part of maintaining your OpenRAG deployment.
+
+Most OpenRAG services run in containers.
+However, some services, like Docling, run directly on the local machine.
+
+If you [installed OpenRAG](/install-options) with the automated installer script, `uv`, or `uvx`, you can use the [Terminal User Interface (TUI)](/tui) to manage your OpenRAG configuration and services.
+
+For [self-managed deployments](/docker), run Docker or Podman commands to manage your OpenRAG services.
+
+## Monitor services
+
+
+
+
+* **TUI Status menu**: In the **Status** menu (3), you can access streaming logs for all OpenRAG services.
+Select the service you want to view, and then press l.
+To copy the logs, click **Copy to Clipboard**.
+
+* **TUI Diagnostics menu**: The TUI's **Diagnostics** menu (4) provides health monitoring for your container runtimes and monitoring of your OpenSearch instance.
+
+* **Docling**: See [Stop, start, and inspect native services](#start-native-services).
+
+
+
+
+* **Containers**: Get container logs with [`docker compose logs`](https://docs.docker.com/reference/cli/docker/compose/logs/) or [`podman logs`](https://docs.podman.io/en/latest/markdown/podman-logs.1.html).
+
+* **Docling**: See [Stop, start, and inspect native services](#start-native-services).
+
+
+
+
+## Stop and start containers
+
+
+
+
+In the TUI's **Status** menu (3), click **Stop Services** to stop all OpenRAG container-based services.
+Then, click **Start All Services** to restart the OpenRAG containers.
+
+When you click **Start All Services**, the following processes are triggered:
+
+1. OpenRAG automatically detects your container runtime, and then checks if your machine has compatible GPU support by checking for `CUDA`, `NVIDIA_SMI`, and Docker/Podman runtime support. This check determines which Docker Compose file OpenRAG uses because there are separate Docker Compose files for GPU and CPU deployments.
+
+2. OpenRAG pulls the OpenRAG container images with `docker compose pull` if any images are missing.
+
+3. OpenRAG deploys the containers with `docker compose up -d`.
+
+
+
+
+Use [`docker compose down`](https://docs.docker.com/reference/cli/docker/compose/down/) and [`docker compose up -d`](https://docs.docker.com/reference/cli/docker/compose/up/).
+
+To stop or start individual containers, use targeted commands like `docker stop CONTAINER_ID` and `docker start CONTAINER_ID`.
+
+
+
+
+## Stop, start, and inspect native services (Docling) {#start-native-services}
+
+A _native service_ in OpenRAG is a service that runs locally on your machine, not within a container. For example, the `docling serve` process is an OpenRAG native service because this document processing service runs on your local machine, separate from the OpenRAG containers.
+
+
+
+
+From the TUI's **Status** menu (3), click **Native Services** to do the following:
+
+* View the service's status, port, and process ID (PID).
+* Stop, start, and restart native services.
+
+
+
+
+Because the Docling service doesn't run in a container, you must start and stop it manually on the host machine:
+
+* Stop `docling serve`:
+
+ ```bash
+ uv run python scripts/docling_ctl.py stop
+ ```
+
+* Start `docling serve`:
+
+ ```bash
+ uv run python scripts/docling_ctl.py start --port 5001
+ ```
+
+* Check that `docling serve` is running:
+
+ ```bash
+ uv run python scripts/docling_ctl.py status
+ ```
+
+ If `docling serve` is running, the output includes the status, address, and process ID (PID):
+
+ ```text
+ Status: running
+ Endpoint: http://127.0.0.1:5001
+ Docs: http://127.0.0.1:5001/docs
+ PID: 27746
+ ```
+
+
+
+
+## Upgrade services
+
+See [Upgrade OpenRAG](/upgrade).
+
+## Reset containers (destructive) {#reset-containers}
+
+Reset your OpenRAG deployment by recreating the containers and removing some related data.
+
+To completely reset your OpenRAG deployment and delete all OpenRAG data, see [Reinstall OpenRAG](/reinstall).
+
+### Export customized flows before resetting containers {#export-customized-flows-before-resetting-containers}
+
+If you modified the built-in flows or created custom flows in your OpenRAG Langflow instance, and you want to preserve those changes, [export your flows](https://docs.langflow.org/concepts-flows-import) before resetting your OpenRAG containers.
+
+### Factory Reset with the TUI
+
+
+
+1. To destroy and recreate your OpenRAG containers, open the TUI's **Status** menu (3), and then click **Factory Reset**.
+
+2. Repeat the [setup process](/install#setup) to restart the services and launch the OpenRAG app. Your OpenRAG passwords, OAuth credentials (if previously set), and onboarding configuration are restored from the `.env` file.
+
+### Rebuild self-managed containers
+
+This command destroys and recreates the containers. Data stored exclusively on the containers is lost, such as Langflow flows.
+
+If you want to preserve customized flows, see [Export customized flows before resetting containers](#export-customized-flows-before-resetting-containers).
+
+The `.env` file, `config` directory, `./openrag-documents` directory, `./opensearch-data` directory, and the `conversations.json` file are preserved.
+
+```bash title="Docker"
+docker compose up --build --force-recreate --remove-orphans
+```
+
+```bash title="Podman"
+podman compose up --build --force-recreate --remove-orphans
+```
+
+### Destroy and recreate self-managed containers
+
+Use separate commands to destroy and recreate the containers if you want to modify the configuration or delete other OpenRAG data before recreating the containers.
+
+:::warning
+These are destructive operations that reset your OpenRAG deployment to an initial state.
+Destroyed containers and deleted data are lost and cannot be recovered after running this operation.
+:::
+
+1. Destroy the containers, volumes, and local images, and then remove (prune) any additional container objects:
+
+
+
+2. Optional: Remove data that wasn't deleted by the previous commands:
+
+ * OpenRAG's `.env` file
+ * The contents of OpenRAG's `config` directory
+ * The contents of the `./openrag-documents` directory
+ * The contents of the `./opensearch-data` directory
+ * The `conversations.json` file
+
+3. If you deleted the `.env` file, prepare a new `.env` before redeploying the containers.
+For more information, see [Deploy OpenRAG with self-managed services](/docker).
+
+4. Recreate the containers:
+
+
+
+5. Launch the OpenRAG app, and then repeat the [application onboarding process](/docker#application-onboarding).
+
+## See also
+
+* [Uninstall OpenRAG](/uninstall)
\ No newline at end of file
diff --git a/docs/docs/get-started/quickstart.mdx b/docs/docs/get-started/quickstart.mdx
index f8b227bd..fee479a2 100644
--- a/docs/docs/get-started/quickstart.mdx
+++ b/docs/docs/get-started/quickstart.mdx
@@ -6,36 +6,28 @@ slug: /quickstart
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-import PartialWsl from '@site/docs/_partial-wsl-install.mdx';
import PartialIntegrateChat from '@site/docs/_partial-integrate-chat.mdx';
+import PartialPrereqWindows from '@site/docs/_partial-prereq-windows.mdx';
+import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx';
Use this quickstart to install OpenRAG, and then try some of OpenRAG's core features.
## Prerequisites
-This quickstart requires the following:
+
-- An [OpenAI API key](https://platform.openai.com/api-keys).
+* Get an [OpenAI API key](https://platform.openai.com/api-keys).
This quickstart uses OpenAI for simplicity.
-For other providers, see the complete [installation guide](/install).
-
-- [Python](https://www.python.org/downloads/release/python-3100/) version 3.13 or later.
-
-- Microsoft Windows only: To run OpenRAG on Windows, you must use the Windows Subsystem for Linux (WSL).
-
-
- Install WSL for OpenRAG
-
-
-
-
+For other providers, see the other [installation methods](/install-options).
+
## Install OpenRAG
-For this quickstart, install OpenRAG with the automatic installer script and basic setup:
+For this quickstart, install OpenRAG with the automatic installer script and basic setup.
+The script installs OpenRAG dependencies, including Docker or Podman, and then it installs and runs OpenRAG with [`uvx`](https://docs.astral.sh/uv/guides/tools/#running-tools).
-1. Create a directory to store the OpenRAG configuration files, and then change to that directory:
+1. Create a directory for your OpenRAG installation, and then change to that directory:
```bash
mkdir openrag-workspace
@@ -48,40 +40,42 @@ For this quickstart, install OpenRAG with the automatic installer script and bas
bash run_openrag_with_prereqs.sh
```
- This script installs OpenRAG and its dependencies, including Docker or Podman, and it creates a `.env` file and `docker-compose` files in the current working directory.
+ Wait while the installer script prepares your environment and installs OpenRAG.
You might be prompted to install certain dependencies if they aren't already present in your environment.
- This process can take a few minutes.
- Once the environment is ready, OpenRAG starts.
-3. Click **Basic Setup**.
+ The entire process can take a few minutes.
+ Once the environment is ready, the OpenRAG [Terminal User Interface (TUI)](/tui) starts.
-4. Create passwords for your OpenRAG installation's OpenSearch and Langflow services. You can click **Generate Passwords** to automatically generate passwords.
+ 
- The OpenSearch password is required. The Langflow admin password is optional.
- If you don't generate a Langflow admin password, Langflow runs in [autologin mode](https://docs.langflow.org/api-keys-and-authentication#langflow-auto-login) with no password required.
+3. In the TUI, click **Basic Setup**.
- Your passwords are saved in the `.env` file that is used to start OpenRAG.
- You can find this file in your OpenRAG installation directory.
+4. Click **Generate Passwords** to create administrator passwords for your OpenRAG OpenSearch and Langflow services.
-5. Click **Save Configuration**, and then click **Start All Services**.
+5. Leave the **OpenAI API key** field empty.
- Wait a few minutes while the startup process pulls and runs the necessary container images.
- Proceed when you see the following messages in the terminal user interface (TUI):
+6. Click **Save Configuration**, and then click **Start All Services**.
- ```bash
+ This process can take some time while OpenRAG pulls and runs the container images.
+ If all services start successfully, the TUI prints a confirmation message:
+
+ ```text
Services started successfully
Command completed successfully
```
-6. To open the OpenRAG application, go to the TUI main menu, and then click **Open App**.
-Alternatively, in your browser, navigate to `localhost:3000`.
+ Your OpenRAG configuration and passwords are stored in an [OpenRAG `.env` file](/reference/configuration) file that is created automatically in your OpenRAG installation directory, which is the directory where you ran the installer script.
+ Container definitions are stored in the `docker-compose` files in the same directory.
-7. Select the **OpenAI** model provider, enter your OpenAI API key, and then click **Complete**.
+7. Under [**Native Services**](/manage-services), click **Start** to start the Docling service.
- For this quickstart, you can use the default options for the model settings.
+8. From the TUI main menu, click **Open App** to launch the OpenRAG application and start the application onboarding process.
-8. Click through the overview slides for a brief introduction to OpenRAG and basic setup, or click **Skip overview**.
+9. For this quickstart, select the **OpenAI** model provider, enter your OpenAI API key, and then click **Complete**. Use the default settings for all other model options.
+
+10. Click through the overview slides for a brief introduction to OpenRAG, or click **Skip overview**.
You can complete this quickstart without going through the overview.
+The overview demonstrates some basic functionality that is covered in the next section and in other parts of the OpenRAG documentation.
## Load and chat with documents {#chat-with-documents}
@@ -158,9 +152,8 @@ You can send and receive requests with the Langflow API using Python, TypeScript
## Next steps
-* **Reinstall OpenRAG with your preferred settings**: This quickstart used a minimal setup to demonstrate OpenRAG's core functionality.
-It is recommended that you [reinstall OpenRAG](/install#reinstall) with your preferred configuration because some settings are immutable after initial setup.
-For all installation options, see [Install OpenRAG with TUI](/install) and [Install OpenRAG with containers](/docker).
+* **Reinstall OpenRAG with your preferred settings**: This quickstart used `uvx` and a minimal setup to demonstrate OpenRAG's core functionality.
+It is recommended that you [reinstall OpenRAG](/reinstall) with your preferred configuration and [installation method](/install-options).
* **Learn more about OpenRAG**: Explore OpenRAG and the OpenRAG documentation to learn more about its features and functionality.
diff --git a/docs/docs/get-started/reinstall.mdx b/docs/docs/get-started/reinstall.mdx
new file mode 100644
index 00000000..d120f7cd
--- /dev/null
+++ b/docs/docs/get-started/reinstall.mdx
@@ -0,0 +1,90 @@
+---
+title: Reinstall OpenRAG
+slug: /reinstall
+---
+
+import PartialDockerComposeUp from '@site/docs/_partial-docker-compose-up.mdx';
+import PartialDockerComposeDownAndPrune from '@site/docs/_partial-docker-compose-down-and-prune.mdx';
+import PartialDockerStopAll from '@site/docs/_partial-docker-stop-all.mdx';
+import PartialDockerRemoveAndCleanupSteps from '@site/docs/_partial-docker-remove-and-cleanup-steps.mdx';
+import PartialFactorResetWarning from '@site/docs/_partial-factory-reset-warning.mdx';
+
+You can reset your OpenRAG deployment to its initial state by recreating the containers and deleting accessory data, such as the `.env` file and ingested documents.
+
+:::warning
+These are destructive operations that reset your OpenRAG deployment to an initial state.
+Destroyed containers and deleted data are lost and cannot be recovered after running these operations.
+:::
+
+## Export customized flows before reinstalling
+
+If you modified the built-in flows or created custom flows in your OpenRAG Langflow instance, and you want to preserve those changes, [export your flows](https://docs.langflow.org/concepts-flows-import) before reinstalling OpenRAG.
+
+## Reinstall TUI-managed containers
+
+1. In the TUI's **Status** menu (3), click **Factory Reset** to destroy your OpenRAG containers and some related data.
+
+
+
+2. Exit the TUI with q.
+
+3. Optional: Remove data that wasn't deleted by the **Factory Reset** operation.
+For a completely fresh installation, delete all of this data.
+
+ * **OpenRAG's `.env` file**: Contains your OpenRAG configuration, including OpenRAG passwords, API keys, OAuth settings, and other [environment variables](/reference/configuration). If you delete this file, OpenRAG automatically generates a new one after you repeat the setup and onboarding process. Alternatively, you can add a prepopulated `.env` file to your OpenRAG installation directory before restarting OpenRAG.
+ * **The contents of the `./openrag-documents` directory**: Contains documents that you uploaded to OpenRAG. Delete these files to prevent documents from being reingested to your knowledge base after restarting OpenRAG. However, you might want to preserve OpenRAG's [default documents](https://github.com/langflow-ai/openrag/tree/main/openrag-documents).
+
+4. Restart the TUI with `uv run openrag` or `uvx openrag`.
+
+5. Repeat the [setup process](/install#setup) to configure OpenRAG and restart all services.
+Then, launch the OpenRAG app and repeat the [application onboarding process](/install#application-onboarding).
+
+ If OpenRAG detects a `.env` file during setup and onboarding, it automatically populates any OpenRAG passwords, OAuth credentials, and onboarding configuration set in that file.
+
+## Reinstall self-managed containers with `docker compose` or `podman compose`
+
+Use these steps to reinstall OpenRAG containers with streamlined `docker compose` or `podman compose` commands:
+
+1. Destroy the containers, volumes, and local images, and then remove (prune) any additional container objects:
+
+
+
+2. Optional: Remove data that wasn't deleted by the previous commands:
+
+ * OpenRAG's `.env` file
+ * The contents of OpenRAG's `config` directory
+ * The contents of the `./openrag-documents` directory
+ * The contents of the `./opensearch-data` directory
+ * The `conversations.json` file
+
+3. If you deleted the `.env` file, prepare a new `.env` before redeploying the containers.
+For more information, see [Deploy OpenRAG with self-managed services](/docker).
+
+4. Redeploy OpenRAG:
+
+
+
+5. Launch the OpenRAG app, and then repeat the [application onboarding process](/docker#application-onboarding).
+
+## Reinstall self-managed containers with discrete `docker` or `podman` commands
+
+Use these commands to remove and clean up OpenRAG containers with discrete `docker` or `podman` commands.
+
+If you want to reinstall one container, specify the container name in the commands instead of running the commands on all containers.
+
+1. Stop all running containers:
+
+
+
+
+
+7. Optional: Remove data that wasn't deleted by the previous commands:
+
+ * OpenRAG's `.env` file
+ * The contents of OpenRAG's `config` directory
+ * The contents of the `./openrag-documents` directory
+ * The contents of the `./opensearch-data` directory
+ * The `conversations.json` file
+
+8. If you removed all OpenRAG containers, [redeploy OpenRAG](/docker).
+If you removed only one container, redeploy that container with the appropriate `docker run` or `podman run` command.
\ No newline at end of file
diff --git a/docs/docs/get-started/tui.mdx b/docs/docs/get-started/tui.mdx
new file mode 100644
index 00000000..0965478b
--- /dev/null
+++ b/docs/docs/get-started/tui.mdx
@@ -0,0 +1,32 @@
+---
+title: Use the TUI
+slug: /tui
+---
+
+The OpenRAG Terminal User Interface (TUI) provides a simplified and guided experience for configuring, managing, and monitoring your OpenRAG deployment directly from the terminal.
+
+
+
+If you install OpenRAG with the [automatic installer script](/install), [`uv`](/install-uv), or [`uvx`](/install-uvx), you use the TUI to manage your OpenRAG deployment.
+The TUI guides you through the initial setup, automatically manages your OpenRAG `.env` and `docker-compose` files, and provides convenient access to [service management](/manage-services) controls.
+
+In contrast, when you [deploy OpenRAG with self-managed services](/docker), you must manually configure OpenRAG by preparing a `.env` file and using Docker or Podman commands to deploy and manage your OpenRAG services.
+
+## Access the TUI {#access-the-tui}
+
+If you installed OpenRAG with `uv`, access the TUI with `uv run openrag`.
+
+If you installed OpenRAG with the automatic installer script or `uvx`, access the TUI with `uvx openrag`.
+
+## Manage services with the TUI
+
+Use the TUI's **Status** menu (3) and **Diagnostics** menu (4) to access controls and information for your OpenRAG services.
+For more information, see [Manage OpenRAG services](/manage-services).
+
+## Exit the OpenRAG TUI
+
+To exit the OpenRAG TUI, go to the TUI main menu, and then press q.
+
+Your OpenRAG containers continue to run until they are stopped.
+
+To restart the TUI, see [Access the TUI](#access-the-tui).
\ No newline at end of file
diff --git a/docs/docs/get-started/uninstall.mdx b/docs/docs/get-started/uninstall.mdx
new file mode 100644
index 00000000..3ffd3670
--- /dev/null
+++ b/docs/docs/get-started/uninstall.mdx
@@ -0,0 +1,68 @@
+---
+title: Remove OpenRAG
+slug: /uninstall
+---
+
+import PartialDockerComposeDownAndPrune from '@site/docs/_partial-docker-compose-down-and-prune.mdx';
+import PartialDockerStopAll from '@site/docs/_partial-docker-stop-all.mdx';
+import PartialDockerRemoveAndCleanupSteps from '@site/docs/_partial-docker-remove-and-cleanup-steps.mdx';
+
+:::tip
+If you want to reset your OpenRAG containers without removing OpenRAG entirely, see [Reset OpenRAG containers](/manage-services) and [Reinstall OpenRAG](/reinstall).
+:::
+
+## Uninstall TUI-managed deployments
+
+If you used the [automated installer script](/install) or [`uvx`](/install-uvx) to install OpenRAG, clear your `uv` cache (`uv cache clean`) to remove the TUI environment, and then delete the directory containing your OpenRAG configuration files and data (where you would invoke OpenRAG).
+
+If you used [`uv`](/install-uv) to install OpenRAG, run `uv remove openrag` in your Python project.
+
+## Uninstall self-managed deployments
+
+For self-managed services, destroy the containers, prune any additional container objects, delete any remaining OpenRAG files, and then shut down the Docling service.
+
+### Uninstall with `docker compose` or `podman compose`
+
+Use these steps to uninstall a self-managed OpenRAG deployment with streamlined `docker compose` or `podman compose` commands:
+
+1. Destroy the containers, volumes, and local images, and then remove (prune) any additional container objects:
+
+
+
+2. Remove data that wasn't deleted by the previous commands:
+
+ * OpenRAG's `.env` file
+ * The contents of OpenRAG's `config` directory
+ * The contents of the `./openrag-documents` directory
+ * The contents of the `./opensearch-data` directory
+ * The `conversations.json` file
+
+3. Stop `docling-serve`:
+
+ ```bash
+ uv run python scripts/docling_ctl.py stop
+ ```
+
+### Uninstall with discrete `docker` or `podman` commands
+
+Use these commands to uninstall a self-managed OpenRAG deployment with discrete `docker` or `podman` commands:
+
+1. Stop all running containers:
+
+
+
+
+
+7. Remove data that wasn't deleted by the previous commands:
+
+ * OpenRAG's `.env` file
+ * The contents of OpenRAG's `config` directory
+ * The contents of the `./openrag-documents` directory
+ * The contents of the `./opensearch-data` directory
+ * The `conversations.json` file
+
+8. Stop `docling-serve`:
+
+ ```bash
+ uv run python scripts/docling_ctl.py stop
+ ```
\ No newline at end of file
diff --git a/docs/docs/get-started/upgrade.mdx b/docs/docs/get-started/upgrade.mdx
new file mode 100644
index 00000000..22808116
--- /dev/null
+++ b/docs/docs/get-started/upgrade.mdx
@@ -0,0 +1,149 @@
+---
+title: Upgrade OpenRAG
+slug: /upgrade
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+Use these steps to upgrade your OpenRAG deployment to the latest version or a specific version.
+
+## Export customized flows before upgrading
+
+If you modified the built-in flows or created custom flows in your OpenRAG Langflow instance, [export your flows](https://docs.langflow.org/concepts-flows-import) before upgrading.
+This ensure that you won't lose your flows after upgrading, and you can reference the exported flows if there are any breaking changes in the new version.
+
+## Upgrade TUI-managed installations
+
+To upgrade OpenRAG, you need to upgrade the OpenRAG Python package, and then upgrade the OpenRAG containers.
+
+Upgrading the Python package also upgrades Docling by bumping the dependency in `pyproject.toml`.
+
+This is a two-part process because upgrading the OpenRAG Python package updates the Terminal User Interface (TUI) and Python code, but the container versions are controlled by environment variables in your [OpenRAG `.env` file](/reference/configuration).
+
+1. To check for updates, open the TUI's **Status** menu (3), and then click **Upgrade**.
+
+2. If there is an update, stop all OpenRAG services.
+In the **Status** menu, click **Stop Services**.
+
+3. Upgrade the OpenRAG Python package to the latest version from [PyPI](https://pypi.org/project/openrag/).
+The commands to upgrade the package depend on how you installed OpenRAG.
+
+
+
+
+ Use these steps to upgrade the Python package if you installed OpenRAG using the [installer script](/install) or [`uvx`](/install-uvx):
+
+ 1. Navigate to your OpenRAG workspace directory:
+
+ ```bash
+ cd openrag-workspace
+ ```
+
+ 2. Upgrade the OpenRAG package:
+
+ ```bash
+ uvx --from openrag openrag
+ ```
+
+ You can invoke a specific version using any of the [`uvx` version specifiers](https://docs.astral.sh/uv/guides/tools/#requesting-specific-versions), such as `--from`:
+
+ ```bash
+ uvx --from openrag==0.1.30 openrag
+ ```
+
+
+
+
+ Use these steps to upgrade the Python package if you installed OpenRAG with [`uv add`](/install-uv):
+
+ 1. Navigate to your project directory:
+
+ ```bash
+ cd YOUR_PROJECT_NAME
+ ```
+
+ 2. Update OpenRAG to the latest version:
+
+ ```bash
+ uv add --upgrade openrag
+ ```
+
+ To upgrade to a specific version:
+
+ ```bash
+ uv add --upgrade openrag==0.1.33
+ ```
+
+ 3. Start the OpenRAG TUI:
+
+ ```bash
+ uv run openrag
+ ```
+
+
+
+
+ Use these steps to upgrade the Python package if you installed OpenRAG with [`uv pip install`](/install-uv):
+
+ 1. Activate your virtual environment.
+
+ 2. Upgrade OpenRAG:
+
+ ```bash
+ uv pip install --upgrade openrag
+ ```
+
+ To upgrade to a specific version:
+
+ ```bash
+ uv pip install --upgrade openrag==0.1.33
+ ```
+
+ 3. Start the OpenRAG TUI:
+
+ ```bash
+ uv run openrag
+ ```
+
+
+
+
+4. In the OpenRAG TUI, click **Start All Services**, and then wait while the upgraded containers start.
+
+ When you start services after upgrading the Python package, OpenRAG runs `docker compose pull` to get the appropriate container images matching the version specified in your OpenRAG `.env` file. Then, it recreates the containers with the new images using `docker compose up -d --force-recreate`.
+
+ :::tip Pin container versions
+ In the `.env` file, the `OPENRAG_VERSION` [environment variable](/reference/configuration#system-settings) is set to `latest` by default, which pulls the `latest` available container images.
+ To pin a specific container image version, you can set `OPENRAG_VERSION` to the desired container image version, such as `OPENRAG_VERSION=0.1.33`.
+
+ However, when you upgrade the Python package, OpenRAG automatically attempts to keep the `OPENRAG_VERSION` synchronized with the Python package version.
+ You might need to edit the `.env` file after upgrading the Python package to enforce a different container version.
+ The TUI warns you if it detects a version mismatch.
+ :::
+
+ If you get an error that `langflow container already exists` error during upgrade, see [Langflow container already exists during upgrade](/support/troubleshoot#langflow-container-already-exists-during-upgrade).
+
+5. Under [**Native Services**](/manage-services), click **Start** to start the Docling service.
+
+6. When the upgrade process is complete, you can close the **Status** window and continue using OpenRAG.
+
+## Upgrade self-managed containers
+
+To fetch and apply the latest container images while preserving your OpenRAG data, run the commands for your container management tool.
+By default, OpenRAG's `docker-compose` files pull the latest container images.
+
+```bash title="Docker"
+docker compose pull
+docker compose up -d --force-recreate
+```
+
+```bash title="Podman"
+podman compose pull
+podman compose up -d --force-recreate
+```
+
+## See also
+
+* [Manage OpenRAG services](/manage-services)
+* [Troubleshoot OpenRAG](/support/troubleshoot)
\ No newline at end of file
diff --git a/docs/docs/reference/configuration.mdx b/docs/docs/reference/configuration.mdx
index 97d71a2c..9a36ebaa 100644
--- a/docs/docs/reference/configuration.mdx
+++ b/docs/docs/reference/configuration.mdx
@@ -3,13 +3,11 @@ title: Environment variables
slug: /reference/configuration
---
-import Icon from "@site/src/components/icon/icon";
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
+import PartialDockerComposeUp from '@site/docs/_partial-docker-compose-up.mdx';
OpenRAG recognizes environment variables from the following sources:
-* [Environment variables](#configure-environment-variables): Values set in the `.env` file.
+* [Environment variables](#configure-environment-variables): Values set in the `.env` file in the OpenRAG installation directory.
* [Langflow runtime overrides](#langflow-runtime-overrides): Langflow components can set environment variables at runtime.
* [Default or fallback values](#default-values-and-fallbacks): These values are default or fallback values if OpenRAG doesn't find a value.
@@ -25,67 +23,64 @@ Environment variables always take precedence over other variables.
### Set environment variables {#set-environment-variables}
-After you start OpenRAG, you must [stop and restart OpenRAG containers](/install#tui-container-management) to apply any changes you make to the `.env` file.
+Environment variables are either mutable or immutable.
-To set mutable environment variables, do the following:
+If you edit mutable environment variables, you can apply the changes by stopping and restarting the OpenRAG services after editing the `.env` file:
-1. Stop OpenRAG with the TUI or Docker Compose.
+1. [Stop the OpenRAG services](/manage-services).
-2. Set the values in the `.env` file:
+2. Edit your `.env` file.
- ```bash
- LOG_LEVEL=DEBUG
- LOG_FORMAT=json
- SERVICE_NAME=openrag-dev
+3. [Restart the OpenRAG services](/manage-services).
+
+If you edit immutable environment variables, you must [redeploy OpenRAG](/reinstall) with your modified `.env` file.
+For example, with self-managed services, do the following:
+
+1. Stop the deployment:
+
+ ```bash title="Docker"
+ docker compose down
```
-3. Start OpenRAG with the TUI or Docker Compose.
-
-Certain environment variables that you set during [application onboarding](/install#application-onboarding), such as provider API keys and provider endpoints, require resetting the containers after modifying the `.env` file.
-
-To change immutable variables with TUI-managed containers, you must [reinstall OpenRAG](/install#reinstall) and either delete or modify the `.env` file before you repeat the setup and onboarding process in the TUI.
-
-To change immutable variables with self-managed containers, do the following:
-
-1. Stop OpenRAG with Docker Compose.
-
-2. Remove the containers:
-
- ```bash
- docker-compose down
+ ```bash title="Podman"
+ podman compose down
```
-3. Update the values in your `.env` file.
+2. Edit your `.env` file.
-4. Start OpenRAG with Docker Compose:
+3. Redeploy OpenRAG:
- ```bash
- docker-compose up -d
- ```
+
-5. Repeat [application onboarding](/install#application-onboarding). The values in your `.env` file are automatically populated.
+4. Restart the Docling service.
+
+5. Launch the OpenRAG app, and then repeat the [application onboarding process](/install#application-onboarding). The values in your `.env` file are automatically populated.
## Supported environment variables
All OpenRAG configuration can be controlled through environment variables.
-### AI provider settings
+### Model provider settings {#model-provider-settings}
Configure which models and providers OpenRAG uses to generate text and embeddings.
-These are initially set during [application onboarding](/install#application-onboarding).
-Some values are immutable and can only be changed by recreating the OpenRAG containers, as explained in [Set environment variables](#set-environment-variables).
+You only need to provide credentials for the providers you are using in OpenRAG.
+
+These variables are initially set during the [application onboarding process](/install#application-onboarding).
+Some of these variables are immutable and can only be changed by redeploying OpenRAG, as explained in [Set environment variables](#set-environment-variables).
| Variable | Default | Description |
|----------|---------|-------------|
-| `EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model for generating vector embeddings for documents in the knowledge base and similarity search queries. Can be changed after application onboarding. Accepts one or more models. |
+| `EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model for generating vector embeddings for documents in the knowledge base and similarity search queries. Can be changed after the application onboarding process. Accepts one or more models. |
| `LLM_MODEL` | `gpt-4o-mini` | Language model for language processing and text generation in the **Chat** feature. |
-| `MODEL_PROVIDER` | `openai` | Model provider, such as OpenAI or IBM watsonx.ai. |
-| `OPENAI_API_KEY` | Not set | Optional OpenAI API key for the default model. For other providers, use `PROVIDER_API_KEY`. |
-| `PROVIDER_API_KEY` | Not set | API key for the model provider. |
-| `PROVIDER_ENDPOINT` | Not set | Custom provider endpoint for the IBM and Ollama model providers. Leave unset for other model providers. |
-| `PROVIDER_PROJECT_ID` | Not set | Project ID for the IBM watsonx.ai model provider only. Leave unset for other model providers. |
+| `MODEL_PROVIDER` | `openai` | Model provider, as one of `openai`, `watsonx`, `ollama`, or `anthropic`. |
+| `ANTHROPIC_API_KEY` | Not set | API key for the Anthropic language model provider. |
+| `OPENAI_API_KEY` | Not set | API key for the OpenAI model provider, which is also the default model provider. |
+| `OLLAMA_ENDPOINT` | Not set | Custom provider endpoint for the Ollama model provider. |
+| `WATSONX_API_KEY` | Not set | API key for the IBM watsonx.ai model provider. |
+| `WATSONX_ENDPOINT` | Not set | Custom provider endpoint for the IBM watsonx.ai model provider. |
+| `WATSONX_PROJECT_ID` | Not set | Project ID for the IBM watsonx.ai model provider. |
-### Document processing
+### Document processing settings {#document-processing-settings}
Control how OpenRAG [processes and ingests documents](/ingestion) into your knowledge base.
@@ -99,36 +94,42 @@ Control how OpenRAG [processes and ingests documents](/ingestion) into your know
| `OPENRAG_DOCUMENTS_PATHS` | `./openrag-documents` | Document paths for ingestion. |
| `PICTURE_DESCRIPTIONS_ENABLED` | `false` | Enable picture descriptions. |
-### Langflow settings
+### Langflow settings {#langflow-settings}
-Configure Langflow authentication.
+Configure the OpenRAG Langflow server's authentication, contact point, and built-in flow definitions.
+
+:::info
+The `LANGFLOW_SUPERUSER_PASSWORD` is set in your `.env` file, and this value determines the default values for several other Langflow authentication variables.
+
+If the `LANGFLOW_SUPERUSER_PASSWORD` variable isn't set, then the Langflow server starts _without_ authentication enabled.
+
+For better security, it is recommended to set `LANGFLOW_SUPERUSER_PASSWORD` so the [Langflow server starts with authentication enabled](https://docs.langflow.org/api-keys-and-authentication#start-a-langflow-server-with-authentication-enabled).
+:::
| Variable | Default | Description |
|----------|---------|-------------|
-| `LANGFLOW_AUTO_LOGIN` | `False` | Enable auto-login for Langflow. |
-| `LANGFLOW_CHAT_FLOW_ID` | Built-in flow ID | This value is automatically set to the ID of the chat [flow](/agents). The default value is found in [`.env.example`](https://github.com/langflow-ai/openrag/blob/main/.env.example). Only change this value if you explicitly don't want to use this built-in flow. |
-| `LANGFLOW_ENABLE_SUPERUSER_CLI` | `False` | Enable superuser privileges for Langflow CLI commands. |
-| `LANGFLOW_INGEST_FLOW_ID` | Built-in flow ID | This value is automatically set to the ID of the ingestion [flow](/agents). The default value is found in [`.env.example`](https://github.com/langflow-ai/openrag/blob/main/.env.example). Only change this value if you explicitly don't want to use this built-in flow. |
-| `LANGFLOW_KEY` | Automatically generated | Explicit Langflow API key. |
-| `LANGFLOW_NEW_USER_IS_ACTIVE` | `False` | Whether new Langflow users are active by default. |
-| `LANGFLOW_PUBLIC_URL` | `http://localhost:7860` | Public URL for the Langflow instance. |
-| `LANGFLOW_SECRET_KEY` | Not set | Secret key for Langflow internal operations. |
-| `LANGFLOW_SUPERUSER` | None, must be explicitly set | Langflow admin username. Required. |
-| `LANGFLOW_SUPERUSER_PASSWORD` | None, must be explicitly set | Langflow admin password. Required. |
+| `LANGFLOW_AUTO_LOGIN` | Determined by `LANGFLOW_SUPERUSER_PASSWORD` | Whether to enable [auto-login mode](https://docs.langflow.org/api-keys-and-authentication#langflow-auto-login) for the Langflow visual editor and CLI. If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then `LANGFLOW_AUTO_LOGIN` is `True` and auto-login mode is enabled. If `LANGFLOW_SUPERUSER_PASSWORD` is set, then `LANGFLOW_AUTO_LOGIN` is `False` and auto-login mode is disabled. Langflow API calls always require authentication with a Langflow API key regardless of the auto-login setting. |
+| `LANGFLOW_ENABLE_SUPERUSER_CLI` | Determined by `LANGFLOW_SUPERUSER_PASSWORD` | Whether to enable the [Langflow CLI `langflow superuser` command](https://docs.langflow.org/api-keys-and-authentication#langflow-enable-superuser-cli). If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then `LANGFLOW_ENABLE_SUPERUSER_CLI` is `True` and superuser accounts can be created with the Langflow CLI. If `LANGFLOW_SUPERUSER_PASSWORD` is set, then `LANGFLOW_ENABLE_SUPERUSER_CLI` is `False` and the `langflow superuser` command is disabled. |
+| `LANGFLOW_NEW_USER_IS_ACTIVE` | Determined by `LANGFLOW_SUPERUSER_PASSWORD` | Whether new [Langflow user accounts are active by default](https://docs.langflow.org/api-keys-and-authentication#langflow-new-user-is-active). If `LANGFLOW_SUPERUSER_PASSWORD` isn't set, then `LANGFLOW_NEW_USER_IS_ACTIVE` is `True` and new user accounts are active by default. If `LANGFLOW_SUPERUSER_PASSWORD` is set, then `LANGFLOW_NEW_USER_IS_ACTIVE` is `False` and new user accounts are inactive by default. |
+| `LANGFLOW_PUBLIC_URL` | `http://localhost:7860` | Public URL for the Langflow instance. Forms the base URL for Langflow API calls and other interfaces with your OpenRAG Langflow instance. |
+| `LANGFLOW_KEY` | Automatically generated | A Langflow API key to run flows with Langflow API calls. Because Langflow API keys are server-specific, allow OpenRAG to generate this key initially. You can create additional Langflow API keys after deploying OpenRAG. |
+| `LANGFLOW_SECRET_KEY` | Automatically generated | Secret encryption key for Langflow internal operations. It is recommended to [generate your own Langflow secret key](https://docs.langflow.org/api-keys-and-authentication#langflow-secret-key) for this variable. If this variable isn't set, then Langflow generates a secret key automatically. |
+| `LANGFLOW_SUPERUSER` | `admin` | Username for the Langflow administrator user. |
+| `LANGFLOW_SUPERUSER_PASSWORD` | Not set | Langflow administrator password. If this variable isn't set, then the Langflow server starts _without_ authentication enabled. It is recommended to set `LANGFLOW_SUPERUSER_PASSWORD` so the [Langflow server starts with authentication enabled](https://docs.langflow.org/api-keys-and-authentication#start-a-langflow-server-with-authentication-enabled). |
| `LANGFLOW_URL` | `http://localhost:7860` | URL for the Langflow instance. |
-| `NUDGES_FLOW_ID` | Built-in flow ID | This value is automatically set to the ID of the nudges [flow](/agents). The default value is found in [`.env.example`](https://github.com/langflow-ai/openrag/blob/main/.env.example). Only change this value if you explicitly don't want to use this built-in flow. |
+| `LANGFLOW_CHAT_FLOW_ID`, `LANGFLOW_INGEST_FLOW_ID`, `NUDGES_FLOW_ID` | Built-in flow IDs | These variables are set automatically to the IDs of the chat, ingestion, and nudges [flows](/agents). The default values are found in [`.env.example`](https://github.com/langflow-ai/openrag/blob/main/.env.example). Only change these values if you want to replace a built-in flow with your own custom flow. The flow JSON must be present in your version of the OpenRAG codebase. For example, if you [deploy self-managed services](/docker), you can add the flow JSON to your local clone of the OpenRAG repository before deploying OpenRAG. |
| `SYSTEM_PROMPT` | `You are a helpful AI assistant with access to a knowledge base. Answer questions based on the provided context.` | System prompt instructions for the agent driving the **Chat** flow. |
### OAuth provider settings
-Configure OAuth providers and external service integrations.
+Configure [OAuth providers](/ingestion#oauth-ingestion) and external service integrations.
| Variable | Default | Description |
|----------|---------|-------------|
-| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | - | AWS integrations. |
-| `GOOGLE_OAUTH_CLIENT_ID` / `GOOGLE_OAUTH_CLIENT_SECRET` | - | Google OAuth authentication. |
-| `MICROSOFT_GRAPH_OAUTH_CLIENT_ID` / `MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET` | - | Microsoft OAuth. |
-| `WEBHOOK_BASE_URL` | - | Base URL for webhook endpoints. |
+| `AWS_ACCESS_KEY_ID` `AWS_SECRET_ACCESS_KEY` | Not set | Enable access to AWS S3 with an [AWS OAuth app](https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html) integration. |
+| `GOOGLE_OAUTH_CLIENT_ID` `GOOGLE_OAUTH_CLIENT_SECRET` | Not set | Enable the [Google OAuth client](https://developers.google.com/identity/protocols/oauth2) integration. You can generate these values in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials). |
+| `MICROSOFT_GRAPH_OAUTH_CLIENT_ID` `MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET` | Not set | Enable the [Microsoft Graph OAuth client](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth) integration by providing [Azure application registration credentials for SharePoint and OneDrive](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/app-registration?view=odsp-graph-online). |
+| `WEBHOOK_BASE_URL` | Not set | Base URL for OAuth connector webhook endpoints. If this variable isn't set, a default base URL is used. |
### OpenSearch settings
@@ -136,10 +137,10 @@ Configure OpenSearch database authentication.
| Variable | Default | Description |
|----------|---------|-------------|
-| `OPENSEARCH_HOST` | `localhost` | OpenSearch host. |
-| `OPENSEARCH_PASSWORD` | - | Password for OpenSearch admin user. Required. |
-| `OPENSEARCH_PORT` | `9200` | OpenSearch port. |
-| `OPENSEARCH_USERNAME` | `admin` | OpenSearch username. |
+| `OPENSEARCH_HOST` | `localhost` | OpenSearch instance host. |
+| `OPENSEARCH_PORT` | `9200` | OpenSearch instance port. |
+| `OPENSEARCH_USERNAME` | `admin` | OpenSearch administrator username. |
+| `OPENSEARCH_PASSWORD` | Must be set at start up | Required. OpenSearch administrator password. Must adhere to the [OpenSearch password complexity requirements](https://docs.opensearch.org/latest/security/configuration/demo-configuration/#setting-up-a-custom-admin-password). You must set this directly in the `.env` or in the TUI's [**Basic/Advanced Setup**](/install#setup). |
### System settings
@@ -150,10 +151,10 @@ Configure general system components, session management, and logging.
| `LANGFLOW_KEY_RETRIES` | `15` | Number of retries for Langflow key generation. |
| `LANGFLOW_KEY_RETRY_DELAY` | `2.0` | Delay between retries in seconds. |
| `LANGFLOW_VERSION` | `OPENRAG_VERSION` | Langflow Docker image version. By default, OpenRAG uses the `OPENRAG_VERSION` for the Langflow Docker image version. |
-| `LOG_FORMAT` | Disabled | Set to `json` to enabled JSON-formatted log output. |
-| `LOG_LEVEL` | `INFO` | Logging level (DEBUG, INFO, WARNING, ERROR). |
+| `LOG_FORMAT` | Not set | Set to `json` to enabled JSON-formatted log output. If this variable isn't set, then the default logging format is used. |
+| `LOG_LEVEL` | `INFO` | Logging level. Can be one of `DEBUG`, `INFO`, `WARNING`, or `ERROR`. `DEBUG` provides the most detailed logs but can impact performance. |
| `MAX_WORKERS` | `1` | Maximum number of workers for document processing. |
-| `OPENRAG_VERSION` | `latest` | The version of the OpenRAG Docker images to run. For more information, see [Upgrade OpenRAG](/install#upgrade) |
+| `OPENRAG_VERSION` | `latest` | The version of the OpenRAG Docker images to run. For more information, see [Upgrade OpenRAG](/upgrade) |
| `SERVICE_NAME` | `openrag` | Service name for logging. |
| `SESSION_SECRET` | Automatically generated | Session management. |
diff --git a/docs/docs/support/troubleshoot.mdx b/docs/docs/support/troubleshoot.mdx
index 546bddf2..958fa102 100644
--- a/docs/docs/support/troubleshoot.mdx
+++ b/docs/docs/support/troubleshoot.mdx
@@ -3,15 +3,13 @@ title: Troubleshoot OpenRAG
slug: /support/troubleshoot
---
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
This page provides troubleshooting advice for issues you might encounter when using OpenRAG or contributing to OpenRAG.
## OpenSearch fails to start
-Check that `OPENSEARCH_PASSWORD` set in [Environment variables](/reference/configuration) meets requirements.
-The password must contain at least 8 characters, and must contain at least one uppercase letter, one lowercase letter, one digit, and one special character that is strong.
+Check that the value of the `OPENSEARCH_PASSWORD` [environment variable](/reference/configuration) meets the [OpenSearch password complexity requirements](https://docs.opensearch.org/latest/security/configuration/demo-configuration/#setting-up-a-custom-admin-password).
+
+If you need to change the password, you must [reset the OpenRAG services](/manage-services).
## OpenRAG fails to start from the TUI with operation not supported
@@ -33,7 +31,8 @@ Replace `VERSION` with your installed Python version, such as `3.13`.
## Langflow connection issues
-Verify the `LANGFLOW_SUPERUSER` credentials set in [Environment variables](/reference/configuration) are correct.
+Verify that the value of the `LANGFLOW_SUPERUSER` environment variable is correct.
+For more information about this variable and how this variable controls Langflow access, see [Langflow settings](/reference/configuration#langflow-settings).
## Container out of memory errors
@@ -53,31 +52,52 @@ podman machine start
## Port conflicts
-Ensure ports 3000, 7860, 8000, 9200, 5601 are available.
+With the default [environment variable](/reference/configuration) values, OpenRAG requires the following ports to be available on the host machine:
+
+* 3000: Langflow application
+* 5001: Docling local ingestion service
+* 5601: OpenSearch Dashboards
+* 7860: Docling UI
+* 8000: Docling API
+* 9200: OpenSearch service
## OCR ingestion fails (easyocr not installed)
-If Docling ingestion fails with an OCR-related error and mentions `easyocr` is missing, this is likely due to a stale `uv` cache.
+Docling ingestion can fail with an OCR-related error that mentions `easyocr` is missing.
+This is likely due to a stale `uv` cache when you [install OpenRAG with `uvx`](/install-uvx).
-`easyocr` is already included as a dependency in OpenRAG's `pyproject.toml`. Project-managed installations using `uv sync` and `uv run` always sync dependencies directly from your `pyproject.toml`, so they should have `easyocr` installed.
+When you invoke OpenRAG with `uvx openrag`, `uvx` creates a cached, ephemeral environment that doesn't modify your project.
+The location and path of this cache depends on your operating system.
+For example, on macOS, this is typically a user cache directory, such as `/Users/USER_NAME/.cache/uv`.
-If you're running OpenRAG with `uvx openrag`, `uvx` creates a cached, ephemeral environment that doesn't modify your project. This cache can become stale.
+This cache can become stale, producing errors like missing dependencies.
-On macOS, this cache directory is typically a user cache directory such as `/Users/USER_NAME/.cache/uv`.
+1. [Exit the TUI](/tui).
-1. To clear the uv cache, run:
+2. Clear the `uv` cache:
```bash
uv cache clean
```
-2. Start OpenRAG:
+ To clear the OpenRAG cache only, run:
+
+ ```bash
+ uv cache clean openrag
+ ```
+
+3. Invoke OpenRAG to restart the TUI:
```bash
uvx openrag
```
-If you don't need OCR, you can disable OCR-based processing in your ingestion settings to avoid requiring `easyocr`.
+4. Click **Open App**, and then retry document ingestion.
+
+If you install OpenRAG with `uv`, dependencies are synced directly from your `pyproject.toml` file.
+This should automatically install `easyocr` because `easyocr` is included as a dependency in OpenRAG's `pyproject.toml`.
+
+If you don't need OCR, you can disable OCR-based processing in your [ingestion settings](/knowledge#knowledge-ingestion-settings) to avoid requiring `easyocr`.
## Upgrade fails due to Langflow container already exists {#langflow-container-already-exists-during-upgrade}
@@ -87,50 +107,33 @@ To resolve this issue, do the following:
1. Remove only the Langflow container:
-
-
-
1. Stop the Langflow container:
- ```bash
+ ```bash title="Docker"
+ docker stop langflow
+ ```
+
+ ```bash title="Podman"
podman stop langflow
```
2. Remove the Langflow container:
- ```bash
- podman rm langflow --force
- ```
-
-
-
-
- 1. Stop the Langflow container:
-
- ```bash
- docker stop langflow
- ```
-
- 2. Remove the Langflow container:
-
- ```bash
+ ```bash title="Docker"
docker rm langflow --force
```
-
-
+ ```bash title="Podman"
+ podman rm langflow --force
+ ```
-2. Retry the upgrade:
+2. Retry the [upgrade](/upgrade).
- * [Upgrade self-managed containers](/docker#upgrade-containers)
- * [Upgrade TUI-managed containers](/install#upgrade-containers)
+3. If reinstalling the Langflow container doesn't resolve the issue, then you must [reset all containers](/manage-services) or [reinstall OpenRAG](/reinstall).
-3. If reinstalling the Langflow container doesn't resolve the issue, you must reset your OpenRAG deployment:
+4. Retry the [upgrade](/upgrade).
- * [Reset self-managed containers](/docker#reset-containers)
- * [Reset TUI-managed containers](/install#reset-containers)
-
-4. Retry the upgrade.
+ If no updates are available after reinstalling OpenRAG, then you reinstalled at the latest version, and your deployment is up to date.
## Document ingestion or similarity search issues
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index 4f75ae2c..839ca12f 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -124,6 +124,7 @@ const config = {
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
+ additionalLanguages: ['bash', 'docker', 'yaml'],
},
mermaid: {
theme: {light: 'neutral', dark: 'forest'},
diff --git a/docs/sidebars.js b/docs/sidebars.js
index 3549d62e..f4f7ebfd 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -22,8 +22,39 @@ const sidebars = {
label: "About OpenRAG"
},
"get-started/quickstart",
- "get-started/install",
- "get-started/docker",
+ {
+ type: "category",
+ label: "Installation",
+ items: [
+ "get-started/install-options",
+ { type: "doc",
+ id: "get-started/install",
+ label: "Run the installer script",
+ },
+ { type: "doc",
+ id: "get-started/install-uv",
+ label: "Install OpenRAG with uv",
+ },
+ "get-started/install-uvx",
+ { type: "doc",
+ id: "get-started/install-windows",
+ label: "Install OpenRAG on Windows",
+ },
+ { type: "doc",
+ id: "get-started/docker",
+ label: "Deploy self-managed services",
+ },
+ "get-started/upgrade",
+ "get-started/reinstall",
+ "get-started/uninstall",
+ ],
+ },
+ "get-started/tui",
+ {
+ type: "doc",
+ id: "get-started/manage-services",
+ label: "Manage services",
+ },
{
type: "doc",
id: "core-components/agents",
diff --git a/flows/openrag_url_mcp.json b/flows/openrag_url_mcp.json
index 1fb93dea..8bd56e0c 100644
--- a/flows/openrag_url_mcp.json
+++ b/flows/openrag_url_mcp.json
@@ -429,6 +429,91 @@
"sourceHandle": "{œdataTypeœ:œEmbeddingModelœ,œidœ:œEmbeddingModel-Rp0iIœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}",
"target": "OpenSearchVectorStoreComponentMultimodalMultiEmbedding-PMGGV",
"targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œOpenSearchVectorStoreComponentMultimodalMultiEmbedding-PMGGVœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "URLComponent",
+ "id": "URLComponent-lnA0q",
+ "name": "page_results",
+ "output_types": [
+ "DataFrame"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "df",
+ "id": "DataFrameOperations-NpdW5",
+ "inputTypes": [
+ "DataFrame"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "xy-edge__URLComponent-lnA0q{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-lnA0qœ,œnameœ:œpage_resultsœ,œoutput_typesœ:[œDataFrameœ]}-DataFrameOperations-NpdW5{œfieldNameœ:œdfœ,œidœ:œDataFrameOperations-NpdW5œ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "URLComponent-lnA0q",
+ "sourceHandle": "{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-lnA0qœ,œnameœ:œpage_resultsœ,œoutput_typesœ:[œDataFrameœ]}",
+ "target": "DataFrameOperations-NpdW5",
+ "targetHandle": "{œfieldNameœ:œdfœ,œidœ:œDataFrameOperations-NpdW5œ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "DataFrameOperations",
+ "id": "DataFrameOperations-NpdW5",
+ "name": "output",
+ "output_types": [
+ "DataFrame"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_data",
+ "id": "ParserComponent-1eim1",
+ "inputTypes": [
+ "DataFrame",
+ "Data"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "xy-edge__DataFrameOperations-NpdW5{œdataTypeœ:œDataFrameOperationsœ,œidœ:œDataFrameOperations-NpdW5œ,œnameœ:œoutputœ,œoutput_typesœ:[œDataFrameœ]}-ParserComponent-1eim1{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-1eim1œ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "DataFrameOperations-NpdW5",
+ "sourceHandle": "{œdataTypeœ:œDataFrameOperationsœ,œidœ:œDataFrameOperations-NpdW5œ,œnameœ:œoutputœ,œoutput_typesœ:[œDataFrameœ]}",
+ "target": "ParserComponent-1eim1",
+ "targetHandle": "{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-1eim1œ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ParserComponent",
+ "id": "ParserComponent-1eim1",
+ "name": "parsed_text",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "new_column_value",
+ "id": "DataFrameOperations-hqIoy",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ParserComponent-1eim1{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-1eim1œ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-DataFrameOperations-hqIoy{œfieldNameœ:œnew_column_valueœ,œidœ:œDataFrameOperations-hqIoyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ParserComponent-1eim1",
+ "sourceHandle": "{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-1eim1œ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}",
+ "target": "DataFrameOperations-hqIoy",
+ "targetHandle": "{œfieldNameœ:œnew_column_valueœ,œidœ:œDataFrameOperations-hqIoyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}"
}
],
"nodes": [
@@ -706,7 +791,7 @@
"frozen": false,
"icon": "layout-template",
"legacy": false,
- "lf_version": "1.6.0",
+ "lf_version": "1.7.0.dev21",
"metadata": {
"code_hash": "4c72ce0f2e34",
"dependencies": {
@@ -1051,8 +1136,8 @@
"width": 320
},
"position": {
- "x": 1253.2399253814751,
- "y": 1554.2313683997174
+ "x": 417.1342145817257,
+ "y": 1355.0755805523784
},
"selected": false,
"type": "genericNode"
@@ -1089,7 +1174,7 @@
],
"frozen": false,
"icon": "table",
- "last_updated": "2025-11-26T06:11:22.958Z",
+ "last_updated": "2025-12-12T20:28:32.647Z",
"legacy": false,
"metadata": {
"code_hash": "904f4eaebccd",
@@ -1135,7 +1220,7 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"ascending": {
@@ -1333,7 +1418,7 @@
],
"list": false,
"list_add_label": "Add More",
- "load_from_db": true,
+ "load_from_db": false,
"name": "new_column_value",
"override_skip": false,
"placeholder": "",
@@ -1345,7 +1430,7 @@
"trace_as_metadata": true,
"track_in_telemetry": false,
"type": "str",
- "value": "FILENAME"
+ "value": ""
},
"num_rows": {
"_input_type": "IntInput",
@@ -1501,8 +1586,8 @@
"width": 320
},
"position": {
- "x": 1601.8752590736613,
- "y": 1442.944202002645
+ "x": 1578.348410746631,
+ "y": 1137.0951737512514
},
"selected": false,
"type": "genericNode"
@@ -1539,7 +1624,7 @@
],
"frozen": false,
"icon": "table",
- "last_updated": "2025-11-26T06:11:22.960Z",
+ "last_updated": "2025-12-12T20:28:32.648Z",
"legacy": false,
"metadata": {
"code_hash": "904f4eaebccd",
@@ -1585,7 +1670,7 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"ascending": {
@@ -1989,7 +2074,7 @@
],
"frozen": false,
"icon": "table",
- "last_updated": "2025-11-26T06:11:22.961Z",
+ "last_updated": "2025-12-12T20:28:32.648Z",
"legacy": false,
"metadata": {
"code_hash": "904f4eaebccd",
@@ -2035,7 +2120,7 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"ascending": {
@@ -2435,6 +2520,7 @@
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
+ "lf_version": "1.7.0.dev21",
"metadata": {
"code_hash": "7a26c54d89ed",
"dependencies": {
@@ -2698,8 +2784,8 @@
"width": 320
},
"position": {
- "x": 850.439672560931,
- "y": 1627.238751925257
+ "x": 2.9942378786288373,
+ "y": 1375.037939780366
},
"selected": false,
"type": "genericNode"
@@ -3042,7 +3128,7 @@
],
"frozen": false,
"icon": "binary",
- "last_updated": "2025-11-26T06:11:22.856Z",
+ "last_updated": "2025-12-12T20:28:32.527Z",
"legacy": false,
"metadata": {
"code_hash": "0e2d6fe67a26",
@@ -3109,12 +3195,12 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"api_base": {
"_input_type": "MessageTextInput",
- "advanced": true,
+ "advanced": false,
"display_name": "API Base URL",
"dynamic": false,
"info": "Base URL for the API. Leave empty for default.",
@@ -3123,7 +3209,7 @@
],
"list": false,
"list_add_label": "Add More",
- "load_from_db": false,
+ "load_from_db": true,
"name": "api_base",
"override_skip": false,
"placeholder": "",
@@ -3135,12 +3221,12 @@
"trace_as_metadata": true,
"track_in_telemetry": false,
"type": "str",
- "value": ""
+ "value": "OLLAMA_BASE_URL"
},
"api_key": {
"_input_type": "SecretStrInput",
"advanced": false,
- "display_name": "OpenAI API Key",
+ "display_name": "API Key (Optional)",
"dynamic": false,
"info": "Model Provider API key",
"input_types": [],
@@ -3151,7 +3237,7 @@
"placeholder": "",
"real_time_refresh": true,
"required": false,
- "show": true,
+ "show": false,
"title_case": false,
"track_in_telemetry": false,
"type": "str",
@@ -3320,9 +3406,9 @@
"info": "Select the embedding model to use",
"name": "model",
"options": [
- "text-embedding-3-small",
- "text-embedding-3-large",
- "text-embedding-ada-002"
+ "embeddinggemma:latest",
+ "mxbai-embed-large:latest",
+ "nomic-embed-text:latest"
],
"options_metadata": [],
"override_skip": false,
@@ -3337,7 +3423,7 @@
"trace_as_metadata": true,
"track_in_telemetry": true,
"type": "str",
- "value": "text-embedding-3-small"
+ "value": "embeddinggemma:latest"
},
"model_kwargs": {
"_input_type": "DictInput",
@@ -3370,20 +3456,20 @@
],
"list": false,
"list_add_label": "Add More",
- "load_from_db": false,
+ "load_from_db": true,
"name": "ollama_base_url",
"override_skip": false,
"placeholder": "",
"real_time_refresh": true,
"required": false,
- "show": false,
+ "show": true,
"title_case": false,
"tool_mode": false,
"trace_as_input": true,
"trace_as_metadata": true,
"track_in_telemetry": false,
"type": "str",
- "value": ""
+ "value": "OLLAMA_BASE_URL"
},
"project_id": {
"_input_type": "MessageTextInput",
@@ -3447,7 +3533,7 @@
"trace_as_metadata": true,
"track_in_telemetry": true,
"type": "str",
- "value": "OpenAI"
+ "value": "Ollama"
},
"request_timeout": {
"_input_type": "FloatInput",
@@ -3518,7 +3604,7 @@
"dragging": false,
"id": "EmbeddingModel-XjV5v",
"measured": {
- "height": 369,
+ "height": 451,
"width": 320
},
"position": {
@@ -4270,7 +4356,7 @@
],
"frozen": false,
"icon": "braces",
- "last_updated": "2025-11-26T06:11:22.857Z",
+ "last_updated": "2025-12-12T20:28:32.528Z",
"legacy": false,
"lf_version": "1.6.3.dev0",
"metadata": {},
@@ -4320,7 +4406,7 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"code": {
@@ -5025,7 +5111,7 @@
],
"frozen": false,
"icon": "binary",
- "last_updated": "2025-11-26T06:11:22.858Z",
+ "last_updated": "2025-12-12T20:28:32.529Z",
"legacy": false,
"metadata": {
"code_hash": "0e2d6fe67a26",
@@ -5092,7 +5178,7 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"api_base": {
@@ -5303,7 +5389,11 @@
"info": "Select the embedding model to use",
"load_from_db": false,
"name": "model",
- "options": [],
+ "options": [
+ "embeddinggemma:latest",
+ "mxbai-embed-large:latest",
+ "nomic-embed-text:latest"
+ ],
"options_metadata": [],
"override_skip": false,
"placeholder": "",
@@ -5317,7 +5407,7 @@
"trace_as_metadata": true,
"track_in_telemetry": true,
"type": "str",
- "value": ""
+ "value": "embeddinggemma:latest"
},
"model_kwargs": {
"_input_type": "DictInput",
@@ -5548,7 +5638,7 @@
],
"frozen": false,
"icon": "binary",
- "last_updated": "2025-11-26T06:11:22.860Z",
+ "last_updated": "2025-12-12T20:28:32.529Z",
"legacy": false,
"metadata": {
"code_hash": "0e2d6fe67a26",
@@ -5615,7 +5705,7 @@
"value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
},
"_frontend_node_folder_id": {
- "value": "131daebd-f11a-4072-9e20-1e1f903d01b0"
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
},
"_type": "Component",
"api_base": {
@@ -6040,21 +6130,668 @@
},
"selected": false,
"type": "genericNode"
+ },
+ {
+ "data": {
+ "description": "Perform various operations on a DataFrame.",
+ "display_name": "DataFrame Operations",
+ "id": "DataFrameOperations-NpdW5",
+ "node": {
+ "base_classes": [
+ "DataFrame"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Perform various operations on a DataFrame.",
+ "display_name": "DataFrame Operations",
+ "documentation": "https://docs.langflow.org/dataframe-operations",
+ "edited": false,
+ "field_order": [
+ "df",
+ "operation",
+ "column_name",
+ "filter_value",
+ "filter_operator",
+ "ascending",
+ "new_column_name",
+ "new_column_value",
+ "columns_to_select",
+ "num_rows",
+ "replace_value",
+ "replacement_value"
+ ],
+ "frozen": false,
+ "icon": "table",
+ "last_updated": "2025-12-12T20:28:32.649Z",
+ "legacy": false,
+ "lf_version": "1.7.0.dev21",
+ "metadata": {
+ "code_hash": "904f4eaebccd",
+ "dependencies": {
+ "dependencies": [
+ {
+ "name": "pandas",
+ "version": "2.2.3"
+ },
+ {
+ "name": "lfx",
+ "version": null
+ }
+ ],
+ "total_dependencies": 2
+ },
+ "module": "custom_components.dataframe_operations"
+ },
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "DataFrame",
+ "group_outputs": false,
+ "loop_types": null,
+ "method": "perform_operation",
+ "name": "output",
+ "options": null,
+ "required_inputs": null,
+ "selected": "DataFrame",
+ "tool_mode": true,
+ "types": [
+ "DataFrame"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_frontend_node_flow_id": {
+ "value": "72c3d17c-2dac-4a73-b48a-6518473d7830"
+ },
+ "_frontend_node_folder_id": {
+ "value": "2bee9dd9-f030-469f-a568-6fcb3a6e7140"
+ },
+ "_type": "Component",
+ "ascending": {
+ "_input_type": "BoolInput",
+ "advanced": false,
+ "display_name": "Sort Ascending",
+ "dynamic": true,
+ "info": "Whether to sort in ascending order.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "ascending",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": true,
+ "type": "bool",
+ "value": true
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "import pandas as pd\n\nfrom lfx.custom.custom_component.component import Component\nfrom lfx.inputs import SortableListInput\nfrom lfx.io import BoolInput, DataFrameInput, DropdownInput, IntInput, MessageTextInput, Output, StrInput\nfrom lfx.log.logger import logger\nfrom lfx.schema.dataframe import DataFrame\n\n\nclass DataFrameOperationsComponent(Component):\n display_name = \"DataFrame Operations\"\n description = \"Perform various operations on a DataFrame.\"\n documentation: str = \"https://docs.langflow.org/dataframe-operations\"\n icon = \"table\"\n name = \"DataFrameOperations\"\n\n OPERATION_CHOICES = [\n \"Add Column\",\n \"Drop Column\",\n \"Filter\",\n \"Head\",\n \"Rename Column\",\n \"Replace Value\",\n \"Select Columns\",\n \"Sort\",\n \"Tail\",\n \"Drop Duplicates\",\n ]\n\n inputs = [\n DataFrameInput(\n name=\"df\",\n display_name=\"DataFrame\",\n info=\"The input DataFrame to operate on.\",\n required=True,\n ),\n SortableListInput(\n name=\"operation\",\n display_name=\"Operation\",\n placeholder=\"Select Operation\",\n info=\"Select the DataFrame operation to perform.\",\n options=[\n {\"name\": \"Add Column\", \"icon\": \"plus\"},\n {\"name\": \"Drop Column\", \"icon\": \"minus\"},\n {\"name\": \"Filter\", \"icon\": \"filter\"},\n {\"name\": \"Head\", \"icon\": \"arrow-up\"},\n {\"name\": \"Rename Column\", \"icon\": \"pencil\"},\n {\"name\": \"Replace Value\", \"icon\": \"replace\"},\n {\"name\": \"Select Columns\", \"icon\": \"columns\"},\n {\"name\": \"Sort\", \"icon\": \"arrow-up-down\"},\n {\"name\": \"Tail\", \"icon\": \"arrow-down\"},\n {\"name\": \"Drop Duplicates\", \"icon\": \"copy-x\"},\n ],\n real_time_refresh=True,\n limit=1,\n ),\n StrInput(\n name=\"column_name\",\n display_name=\"Column Name\",\n info=\"The column name to use for the operation.\",\n dynamic=True,\n show=False,\n ),\n MessageTextInput(\n name=\"filter_value\",\n display_name=\"Filter Value\",\n info=\"The value to filter rows by.\",\n dynamic=True,\n show=False,\n ),\n DropdownInput(\n name=\"filter_operator\",\n display_name=\"Filter Operator\",\n options=[\n \"equals\",\n \"not equals\",\n \"contains\",\n \"not contains\",\n \"starts with\",\n \"ends with\",\n \"greater than\",\n \"less than\",\n ],\n value=\"equals\",\n info=\"The operator to apply for filtering rows.\",\n advanced=False,\n dynamic=True,\n show=False,\n ),\n BoolInput(\n name=\"ascending\",\n display_name=\"Sort Ascending\",\n info=\"Whether to sort in ascending order.\",\n dynamic=True,\n show=False,\n value=True,\n ),\n StrInput(\n name=\"new_column_name\",\n display_name=\"New Column Name\",\n info=\"The new column name when renaming or adding a column.\",\n dynamic=True,\n show=False,\n ),\n MessageTextInput(\n name=\"new_column_value\",\n display_name=\"New Column Value\",\n info=\"The value to populate the new column with.\",\n dynamic=True,\n show=False,\n ),\n StrInput(\n name=\"columns_to_select\",\n display_name=\"Columns to Select\",\n dynamic=True,\n is_list=True,\n show=False,\n ),\n IntInput(\n name=\"num_rows\",\n display_name=\"Number of Rows\",\n info=\"Number of rows to return (for head/tail).\",\n dynamic=True,\n show=False,\n value=5,\n ),\n MessageTextInput(\n name=\"replace_value\",\n display_name=\"Value to Replace\",\n info=\"The value to replace in the column.\",\n dynamic=True,\n show=False,\n ),\n MessageTextInput(\n name=\"replacement_value\",\n display_name=\"Replacement Value\",\n info=\"The value to replace with.\",\n dynamic=True,\n show=False,\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"DataFrame\",\n name=\"output\",\n method=\"perform_operation\",\n info=\"The resulting DataFrame after the operation.\",\n )\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n dynamic_fields = [\n \"column_name\",\n \"filter_value\",\n \"filter_operator\",\n \"ascending\",\n \"new_column_name\",\n \"new_column_value\",\n \"columns_to_select\",\n \"num_rows\",\n \"replace_value\",\n \"replacement_value\",\n ]\n for field in dynamic_fields:\n build_config[field][\"show\"] = False\n\n if field_name == \"operation\":\n # Handle SortableListInput format\n if isinstance(field_value, list):\n operation_name = field_value[0].get(\"name\", \"\") if field_value else \"\"\n else:\n operation_name = field_value or \"\"\n\n # If no operation selected, all dynamic fields stay hidden (already set to False above)\n if not operation_name:\n return build_config\n\n if operation_name == \"Filter\":\n build_config[\"column_name\"][\"show\"] = True\n build_config[\"filter_value\"][\"show\"] = True\n build_config[\"filter_operator\"][\"show\"] = True\n elif operation_name == \"Sort\":\n build_config[\"column_name\"][\"show\"] = True\n build_config[\"ascending\"][\"show\"] = True\n elif operation_name == \"Drop Column\":\n build_config[\"column_name\"][\"show\"] = True\n elif operation_name == \"Rename Column\":\n build_config[\"column_name\"][\"show\"] = True\n build_config[\"new_column_name\"][\"show\"] = True\n elif operation_name == \"Add Column\":\n build_config[\"new_column_name\"][\"show\"] = True\n build_config[\"new_column_value\"][\"show\"] = True\n elif operation_name == \"Select Columns\":\n build_config[\"columns_to_select\"][\"show\"] = True\n elif operation_name in {\"Head\", \"Tail\"}:\n build_config[\"num_rows\"][\"show\"] = True\n elif operation_name == \"Replace Value\":\n build_config[\"column_name\"][\"show\"] = True\n build_config[\"replace_value\"][\"show\"] = True\n build_config[\"replacement_value\"][\"show\"] = True\n elif operation_name == \"Drop Duplicates\":\n build_config[\"column_name\"][\"show\"] = True\n\n return build_config\n\n def perform_operation(self) -> DataFrame:\n df_copy = self.df.copy()\n\n # Handle SortableListInput format for operation\n operation_input = getattr(self, \"operation\", [])\n if isinstance(operation_input, list) and len(operation_input) > 0:\n op = operation_input[0].get(\"name\", \"\")\n else:\n op = \"\"\n\n # If no operation selected, return original DataFrame\n if not op:\n return df_copy\n\n if op == \"Filter\":\n return self.filter_rows_by_value(df_copy)\n if op == \"Sort\":\n return self.sort_by_column(df_copy)\n if op == \"Drop Column\":\n return self.drop_column(df_copy)\n if op == \"Rename Column\":\n return self.rename_column(df_copy)\n if op == \"Add Column\":\n return self.add_column(df_copy)\n if op == \"Select Columns\":\n return self.select_columns(df_copy)\n if op == \"Head\":\n return self.head(df_copy)\n if op == \"Tail\":\n return self.tail(df_copy)\n if op == \"Replace Value\":\n return self.replace_values(df_copy)\n if op == \"Drop Duplicates\":\n return self.drop_duplicates(df_copy)\n msg = f\"Unsupported operation: {op}\"\n logger.error(msg)\n raise ValueError(msg)\n\n def filter_rows_by_value(self, df: DataFrame) -> DataFrame:\n column = df[self.column_name]\n filter_value = self.filter_value\n\n # Handle regular DropdownInput format (just a string value)\n operator = getattr(self, \"filter_operator\", \"equals\") # Default to equals for backward compatibility\n\n if operator == \"equals\":\n mask = column == filter_value\n elif operator == \"not equals\":\n mask = column != filter_value\n elif operator == \"contains\":\n mask = column.astype(str).str.contains(str(filter_value), na=False)\n elif operator == \"not contains\":\n mask = ~column.astype(str).str.contains(str(filter_value), na=False)\n elif operator == \"starts with\":\n mask = column.astype(str).str.startswith(str(filter_value), na=False)\n elif operator == \"ends with\":\n mask = column.astype(str).str.endswith(str(filter_value), na=False)\n elif operator == \"greater than\":\n try:\n # Try to convert filter_value to numeric for comparison\n numeric_value = pd.to_numeric(filter_value)\n mask = column > numeric_value\n except (ValueError, TypeError):\n # If conversion fails, compare as strings\n mask = column.astype(str) > str(filter_value)\n elif operator == \"less than\":\n try:\n # Try to convert filter_value to numeric for comparison\n numeric_value = pd.to_numeric(filter_value)\n mask = column < numeric_value\n except (ValueError, TypeError):\n # If conversion fails, compare as strings\n mask = column.astype(str) < str(filter_value)\n else:\n mask = column == filter_value # Fallback to equals\n\n return DataFrame(df[mask])\n\n def sort_by_column(self, df: DataFrame) -> DataFrame:\n return DataFrame(df.sort_values(by=self.column_name, ascending=self.ascending))\n\n def drop_column(self, df: DataFrame) -> DataFrame:\n return DataFrame(df.drop(columns=[self.column_name]))\n\n def rename_column(self, df: DataFrame) -> DataFrame:\n return DataFrame(df.rename(columns={self.column_name: self.new_column_name}))\n\n def add_column(self, df: DataFrame) -> DataFrame:\n df[self.new_column_name] = [self.new_column_value] * len(df)\n return DataFrame(df)\n\n def select_columns(self, df: DataFrame) -> DataFrame:\n columns = [col.strip() for col in self.columns_to_select]\n return DataFrame(df[columns])\n\n def head(self, df: DataFrame) -> DataFrame:\n return DataFrame(df.head(self.num_rows))\n\n def tail(self, df: DataFrame) -> DataFrame:\n return DataFrame(df.tail(self.num_rows))\n\n def replace_values(self, df: DataFrame) -> DataFrame:\n df[self.column_name] = df[self.column_name].replace(self.replace_value, self.replacement_value)\n return DataFrame(df)\n\n def drop_duplicates(self, df: DataFrame) -> DataFrame:\n return DataFrame(df.drop_duplicates(subset=self.column_name))\n"
+ },
+ "column_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Column Name",
+ "dynamic": true,
+ "info": "The column name to use for the operation.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "column_name",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": ""
+ },
+ "columns_to_select": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Columns to Select",
+ "dynamic": true,
+ "info": "",
+ "list": true,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "columns_to_select",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": [
+ "title"
+ ]
+ },
+ "df": {
+ "_input_type": "DataFrameInput",
+ "advanced": false,
+ "display_name": "DataFrame",
+ "dynamic": false,
+ "info": "The input DataFrame to operate on.",
+ "input_types": [
+ "DataFrame"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "df",
+ "override_skip": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "other",
+ "value": ""
+ },
+ "filter_operator": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Filter Operator",
+ "dynamic": true,
+ "external_options": {},
+ "info": "The operator to apply for filtering rows.",
+ "name": "filter_operator",
+ "options": [
+ "equals",
+ "not equals",
+ "contains",
+ "not contains",
+ "starts with",
+ "ends with",
+ "greater than",
+ "less than"
+ ],
+ "options_metadata": [],
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "toggle": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": true,
+ "type": "str",
+ "value": "equals"
+ },
+ "filter_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Filter Value",
+ "dynamic": true,
+ "info": "The value to filter rows by.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "filter_value",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": ""
+ },
+ "is_refresh": false,
+ "new_column_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "New Column Name",
+ "dynamic": true,
+ "info": "The new column name when renaming or adding a column.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "new_column_name",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": "filename"
+ },
+ "new_column_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "New Column Value",
+ "dynamic": true,
+ "info": "The value to populate the new column with.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "new_column_value",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": ""
+ },
+ "num_rows": {
+ "_input_type": "IntInput",
+ "advanced": false,
+ "display_name": "Number of Rows",
+ "dynamic": true,
+ "info": "Number of rows to return (for head/tail).",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "num_rows",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": true,
+ "type": "int",
+ "value": 5
+ },
+ "operation": {
+ "_input_type": "SortableListInput",
+ "advanced": false,
+ "display_name": "Operation",
+ "dynamic": false,
+ "info": "Select the DataFrame operation to perform.",
+ "limit": 1,
+ "load_from_db": false,
+ "name": "operation",
+ "options": [
+ {
+ "icon": "plus",
+ "name": "Add Column"
+ },
+ {
+ "icon": "minus",
+ "name": "Drop Column"
+ },
+ {
+ "icon": "filter",
+ "name": "Filter"
+ },
+ {
+ "icon": "arrow-up",
+ "name": "Head"
+ },
+ {
+ "icon": "pencil",
+ "name": "Rename Column"
+ },
+ {
+ "icon": "replace",
+ "name": "Replace Value"
+ },
+ {
+ "icon": "columns",
+ "name": "Select Columns"
+ },
+ {
+ "icon": "arrow-up-down",
+ "name": "Sort"
+ },
+ {
+ "icon": "arrow-down",
+ "name": "Tail"
+ },
+ {
+ "icon": "copy-x",
+ "name": "Drop Duplicates"
+ }
+ ],
+ "override_skip": false,
+ "placeholder": "Select Operation",
+ "real_time_refresh": true,
+ "required": false,
+ "search_category": [],
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "sortableList",
+ "value": [
+ {
+ "chosen": false,
+ "icon": "columns",
+ "name": "Select Columns",
+ "selected": false
+ }
+ ]
+ },
+ "replace_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Value to Replace",
+ "dynamic": true,
+ "info": "The value to replace in the column.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "replace_value",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": ""
+ },
+ "replacement_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Replacement Value",
+ "dynamic": true,
+ "info": "The value to replace with.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "replacement_value",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "DataFrameOperations"
+ },
+ "dragging": false,
+ "id": "DataFrameOperations-NpdW5",
+ "measured": {
+ "height": 317,
+ "width": 320
+ },
+ "position": {
+ "x": 856.1961817994918,
+ "y": 1687.1833235248055
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ParserComponent-1eim1",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Extracts text using a template.",
+ "display_name": "Parser",
+ "documentation": "https://docs.langflow.org/parser",
+ "edited": false,
+ "field_order": [
+ "input_data",
+ "mode",
+ "pattern",
+ "sep"
+ ],
+ "frozen": false,
+ "icon": "braces",
+ "legacy": false,
+ "lf_version": "1.7.0.dev21",
+ "metadata": {
+ "code_hash": "3cda25c3f7b5",
+ "dependencies": {
+ "dependencies": [
+ {
+ "name": "lfx",
+ "version": "0.2.0.dev21"
+ }
+ ],
+ "total_dependencies": 1
+ },
+ "module": "lfx.components.processing.parser.ParserComponent"
+ },
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Parsed Text",
+ "group_outputs": false,
+ "method": "parse_combined_text",
+ "name": "parsed_text",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from lfx.custom.custom_component.component import Component\nfrom lfx.helpers.data import safe_convert\nfrom lfx.inputs.inputs import BoolInput, HandleInput, MessageTextInput, MultilineInput, TabInput\nfrom lfx.schema.data import Data\nfrom lfx.schema.dataframe import DataFrame\nfrom lfx.schema.message import Message\nfrom lfx.template.field.base import Output\n\n\nclass ParserComponent(Component):\n display_name = \"Parser\"\n description = \"Extracts text using a template.\"\n documentation: str = \"https://docs.langflow.org/parser\"\n icon = \"braces\"\n\n inputs = [\n HandleInput(\n name=\"input_data\",\n display_name=\"Data or DataFrame\",\n input_types=[\"DataFrame\", \"Data\"],\n info=\"Accepts either a DataFrame or a Data object.\",\n required=True,\n ),\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Parser\", \"Stringify\"],\n value=\"Parser\",\n info=\"Convert into raw string instead of using a template.\",\n real_time_refresh=True,\n ),\n MultilineInput(\n name=\"pattern\",\n display_name=\"Template\",\n info=(\n \"Use variables within curly brackets to extract column values for DataFrames \"\n \"or key values for Data.\"\n \"For example: `Name: {Name}, Age: {Age}, Country: {Country}`\"\n ),\n value=\"Text: {text}\", # Example default\n dynamic=True,\n show=True,\n required=True,\n ),\n MessageTextInput(\n name=\"sep\",\n display_name=\"Separator\",\n advanced=True,\n value=\"\\n\",\n info=\"String used to separate rows/items.\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Parsed Text\",\n name=\"parsed_text\",\n info=\"Formatted text output.\",\n method=\"parse_combined_text\",\n ),\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n \"\"\"Dynamically hide/show `template` and enforce requirement based on `stringify`.\"\"\"\n if field_name == \"mode\":\n build_config[\"pattern\"][\"show\"] = self.mode == \"Parser\"\n build_config[\"pattern\"][\"required\"] = self.mode == \"Parser\"\n if field_value:\n clean_data = BoolInput(\n name=\"clean_data\",\n display_name=\"Clean Data\",\n info=(\n \"Enable to clean the data by removing empty rows and lines \"\n \"in each cell of the DataFrame/ Data object.\"\n ),\n value=True,\n advanced=True,\n required=False,\n )\n build_config[\"clean_data\"] = clean_data.to_dict()\n else:\n build_config.pop(\"clean_data\", None)\n\n return build_config\n\n def _clean_args(self):\n \"\"\"Prepare arguments based on input type.\"\"\"\n input_data = self.input_data\n\n match input_data:\n case list() if all(isinstance(item, Data) for item in input_data):\n msg = \"List of Data objects is not supported.\"\n raise ValueError(msg)\n case DataFrame():\n return input_data, None\n case Data():\n return None, input_data\n case dict() if \"data\" in input_data:\n try:\n if \"columns\" in input_data: # Likely a DataFrame\n return DataFrame.from_dict(input_data), None\n # Likely a Data object\n return None, Data(**input_data)\n except (TypeError, ValueError, KeyError) as e:\n msg = f\"Invalid structured input provided: {e!s}\"\n raise ValueError(msg) from e\n case _:\n msg = f\"Unsupported input type: {type(input_data)}. Expected DataFrame or Data.\"\n raise ValueError(msg)\n\n def parse_combined_text(self) -> Message:\n \"\"\"Parse all rows/items into a single text or convert input to string if `stringify` is enabled.\"\"\"\n # Early return for stringify option\n if self.mode == \"Stringify\":\n return self.convert_to_string()\n\n df, data = self._clean_args()\n\n lines = []\n if df is not None:\n for _, row in df.iterrows():\n formatted_text = self.pattern.format(**row.to_dict())\n lines.append(formatted_text)\n elif data is not None:\n # Use format_map with a dict that returns default_value for missing keys\n class DefaultDict(dict):\n def __missing__(self, key):\n return data.default_value or \"\"\n\n formatted_text = self.pattern.format_map(DefaultDict(data.data))\n lines.append(formatted_text)\n\n combined_text = self.sep.join(lines)\n self.status = combined_text\n return Message(text=combined_text)\n\n def convert_to_string(self) -> Message:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n result = \"\"\n if isinstance(self.input_data, list):\n result = \"\\n\".join([safe_convert(item, clean_data=self.clean_data or False) for item in self.input_data])\n else:\n result = safe_convert(self.input_data or False)\n self.log(f\"Converted to string with length: {len(result)}\")\n\n message = Message(text=result)\n self.status = message\n return message\n"
+ },
+ "input_data": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "Data or DataFrame",
+ "dynamic": false,
+ "info": "Accepts either a DataFrame or a Data object.",
+ "input_types": [
+ "DataFrame",
+ "Data"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "input_data",
+ "override_skip": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "other",
+ "value": ""
+ },
+ "mode": {
+ "_input_type": "TabInput",
+ "advanced": false,
+ "display_name": "Mode",
+ "dynamic": false,
+ "info": "Convert into raw string instead of using a template.",
+ "name": "mode",
+ "options": [
+ "Parser",
+ "Stringify"
+ ],
+ "override_skip": false,
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "track_in_telemetry": true,
+ "type": "tab",
+ "value": "Parser"
+ },
+ "pattern": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "ai_enabled": false,
+ "copy_field": false,
+ "display_name": "Template",
+ "dynamic": true,
+ "info": "Use variables within curly brackets to extract column values for DataFrames or key values for Data.For example: `Name: {Name}, Age: {Age}, Country: {Country}`",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "pattern",
+ "override_skip": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": "{title}"
+ },
+ "sep": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Separator",
+ "dynamic": false,
+ "info": "String used to separate rows/items.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sep",
+ "override_skip": false,
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "track_in_telemetry": false,
+ "type": "str",
+ "value": "\n"
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "ParserComponent"
+ },
+ "dragging": false,
+ "id": "ParserComponent-1eim1",
+ "measured": {
+ "height": 329,
+ "width": 320
+ },
+ "position": {
+ "x": 1205.2726296612543,
+ "y": 1642.3744133698385
+ },
+ "selected": false,
+ "type": "genericNode"
}
],
"viewport": {
- "x": -907.3774606121137,
- "y": -579.4662259269908,
- "zoom": 0.6003073886978839
+ "x": 294.64772127588185,
+ "y": -396.0401212124092,
+ "zoom": 0.5090092700849728
}
},
"description": "This flow is to ingest the URL to open search.",
"endpoint_name": null,
"id": "72c3d17c-2dac-4a73-b48a-6518473d7830",
"is_component": false,
- "locked": true,
- "mcp_enabled": true,
"last_tested_version": "1.7.0.dev21",
+ "mcp_enabled": true,
+ "locked": true,
"name": "OpenSearch URL Ingestion Flow",
"tags": [
"openai",
@@ -6062,4 +6799,4 @@
"rag",
"q-a"
]
-}
+}
\ No newline at end of file
diff --git a/frontend/app/api/queries/useGetAllFiltersQuery.ts b/frontend/app/api/queries/useGetAllFiltersQuery.ts
new file mode 100644
index 00000000..5264d981
--- /dev/null
+++ b/frontend/app/api/queries/useGetAllFiltersQuery.ts
@@ -0,0 +1,36 @@
+import {
+ type UseQueryOptions,
+ useQuery,
+ useQueryClient,
+} from "@tanstack/react-query";
+import type { KnowledgeFilter } from "./useGetFiltersSearchQuery";
+
+export const useGetAllFiltersQuery = (
+ options?: Omit, "queryKey" | "queryFn">,
+) => {
+ const queryClient = useQueryClient();
+
+ async function getAllFilters(): Promise {
+ const response = await fetch("/api/knowledge-filter/search", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ query: "", limit: 1000 }), // Fetch all filters
+ });
+
+ const json = await response.json();
+ if (!response.ok || !json.success) {
+ // ensure we always return a KnowledgeFilter[] to satisfy the return type
+ return [];
+ }
+ return (json.filters || []) as KnowledgeFilter[];
+ }
+
+ return useQuery(
+ {
+ queryKey: ["knowledge-filters", "all"],
+ queryFn: getAllFilters,
+ ...options,
+ },
+ queryClient,
+ );
+};
diff --git a/frontend/app/chat/_components/chat-input.tsx b/frontend/app/chat/_components/chat-input.tsx
index 29b081c5..cd343eda 100644
--- a/frontend/app/chat/_components/chat-input.tsx
+++ b/frontend/app/chat/_components/chat-input.tsx
@@ -1,11 +1,12 @@
+import Fuse from "fuse.js";
import { ArrowRight, Check, Funnel, Loader2, Plus } from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import {
- forwardRef,
- useImperativeHandle,
- useMemo,
- useRef,
- useState,
+ forwardRef,
+ useImperativeHandle,
+ useMemo,
+ useRef,
+ useState,
} from "react";
import { useDropzone } from "react-dropzone";
import TextareaAutosize from "react-textarea-autosize";
@@ -13,585 +14,593 @@ import { toast } from "sonner";
import type { FilterColor } from "@/components/filter-icon-popover";
import { Button } from "@/components/ui/button";
import {
- Popover,
- PopoverAnchor,
- PopoverContent,
+ Popover,
+ PopoverAnchor,
+ PopoverContent,
} from "@/components/ui/popover";
import { useFileDrag } from "@/hooks/use-file-drag";
import { cn } from "@/lib/utils";
-import { useGetFiltersSearchQuery } from "../../api/queries/useGetFiltersSearchQuery";
+import { useGetAllFiltersQuery } from "../../api/queries/useGetAllFiltersQuery";
import type { KnowledgeFilterData } from "../_types/types";
import { FilePreview } from "./file-preview";
import { SelectedKnowledgeFilter } from "./selected-knowledge-filter";
export interface ChatInputHandle {
- focusInput: () => void;
- clickFileInput: () => void;
+ focusInput: () => void;
+ clickFileInput: () => void;
}
interface ChatInputProps {
- input: string;
- loading: boolean;
- isUploading: boolean;
- selectedFilter: KnowledgeFilterData | null;
- parsedFilterData: { color?: FilterColor } | null;
- uploadedFile: File | null;
- onSubmit: (e: React.FormEvent) => void;
- onChange: (value: string) => void;
- onKeyDown: (e: React.KeyboardEvent) => void;
- onFilterSelect: (filter: KnowledgeFilterData | null) => void;
- onFilePickerClick: () => void;
- setSelectedFilter: (filter: KnowledgeFilterData | null) => void;
- setIsFilterHighlighted: (highlighted: boolean) => void;
- onFileSelected: (file: File | null) => void;
+ input: string;
+ loading: boolean;
+ isUploading: boolean;
+ selectedFilter: KnowledgeFilterData | null;
+ parsedFilterData: { color?: FilterColor } | null;
+ uploadedFile: File | null;
+ onSubmit: (e: React.FormEvent) => void;
+ onChange: (value: string) => void;
+ onKeyDown: (e: React.KeyboardEvent) => void;
+ onFilterSelect: (filter: KnowledgeFilterData | null) => void;
+ onFilePickerClick: () => void;
+ setSelectedFilter: (filter: KnowledgeFilterData | null) => void;
+ setIsFilterHighlighted: (highlighted: boolean) => void;
+ onFileSelected: (file: File | null) => void;
}
export const ChatInput = forwardRef(
- (
- {
- input,
- loading,
- isUploading,
- selectedFilter,
- parsedFilterData,
- uploadedFile,
- onSubmit,
- onChange,
- onKeyDown,
- onFilterSelect,
- onFilePickerClick,
- setSelectedFilter,
- setIsFilterHighlighted,
- onFileSelected,
- },
- ref,
- ) => {
- const inputRef = useRef(null);
- const fileInputRef = useRef(null);
- const [textareaHeight, setTextareaHeight] = useState(0);
- const isDragging = useFileDrag();
+ (
+ {
+ input,
+ loading,
+ isUploading,
+ selectedFilter,
+ parsedFilterData,
+ uploadedFile,
+ onSubmit,
+ onChange,
+ onKeyDown,
+ onFilterSelect,
+ onFilePickerClick,
+ setSelectedFilter,
+ setIsFilterHighlighted,
+ onFileSelected,
+ },
+ ref,
+ ) => {
+ const inputRef = useRef(null);
+ const fileInputRef = useRef(null);
+ const [textareaHeight, setTextareaHeight] = useState(0);
+ const isDragging = useFileDrag();
- // Internal state for filter dropdown
- const [isFilterDropdownOpen, setIsFilterDropdownOpen] = useState(false);
- const [filterSearchTerm, setFilterSearchTerm] = useState("");
- const [selectedFilterIndex, setSelectedFilterIndex] = useState(0);
- const [anchorPosition, setAnchorPosition] = useState<{
- x: number;
- y: number;
- } | null>(null);
+ // Internal state for filter dropdown
+ const [isFilterDropdownOpen, setIsFilterDropdownOpen] = useState(false);
+ const [filterSearchTerm, setFilterSearchTerm] = useState("");
+ const [selectedFilterIndex, setSelectedFilterIndex] = useState(0);
+ const [anchorPosition, setAnchorPosition] = useState<{
+ x: number;
+ y: number;
+ } | null>(null);
- // Fetch filters using the query hook
- const { data: availableFilters = [] } = useGetFiltersSearchQuery(
- filterSearchTerm,
- 20,
- { enabled: isFilterDropdownOpen },
- );
+ // Fetch all filters once when dropdown opens
+ const { data: allFilters = [] } = useGetAllFiltersQuery({
+ enabled: isFilterDropdownOpen,
+ });
- // Filter available filters based on search term
- const filteredFilters = useMemo(() => {
- return availableFilters.filter((filter) =>
- filter.name.toLowerCase().includes(filterSearchTerm.toLowerCase()),
- );
- }, [availableFilters, filterSearchTerm]);
+ // Use fuse.js for fuzzy search on client side
+ const filteredFilters = useMemo(() => {
+ if (!filterSearchTerm) {
+ return allFilters.slice(0, 20); // Return first 20 when no search term
+ }
- const { getRootProps, getInputProps } = useDropzone({
- accept: {
- "application/pdf": [".pdf"],
- "application/msword": [".doc"],
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
- [".docx"],
- "text/markdown": [".md"],
- },
- maxFiles: 1,
- disabled: !isDragging,
- onDrop: (acceptedFiles, fileRejections) => {
- if (fileRejections.length > 0) {
- const message = fileRejections.at(0)?.errors.at(0)?.message;
- toast.error(message || "Failed to upload file");
- return;
- }
- onFileSelected(acceptedFiles[0]);
- },
- });
+ const fuse = new Fuse(allFilters, {
+ keys: ["name", "description"],
+ threshold: 0.3, // 0.0 = perfect match, 1.0 = match anything
+ includeScore: true,
+ minMatchCharLength: 1,
+ });
- useImperativeHandle(ref, () => ({
- focusInput: () => {
- inputRef.current?.focus();
- },
- clickFileInput: () => {
- fileInputRef.current?.click();
- },
- }));
+ const results = fuse.search(filterSearchTerm);
+ return results.map((result) => result.item).slice(0, 20);
+ }, [allFilters, filterSearchTerm]);
- const handleFilePickerChange = (e: React.ChangeEvent) => {
- const files = e.target.files;
- if (files && files.length > 0) {
- onFileSelected(files[0]);
- } else {
- onFileSelected(null);
- }
- };
+ const { getRootProps, getInputProps } = useDropzone({
+ accept: {
+ "application/pdf": [".pdf"],
+ "application/msword": [".doc"],
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
+ [".docx"],
+ "text/markdown": [".md"],
+ },
+ maxFiles: 1,
+ disabled: !isDragging,
+ onDrop: (acceptedFiles, fileRejections) => {
+ if (fileRejections.length > 0) {
+ const message = fileRejections.at(0)?.errors.at(0)?.message;
+ toast.error(message || "Failed to upload file");
+ return;
+ }
+ onFileSelected(acceptedFiles[0]);
+ },
+ });
- const onAtClick = () => {
- if (!isFilterDropdownOpen) {
- setIsFilterDropdownOpen(true);
- setFilterSearchTerm("");
- setSelectedFilterIndex(0);
+ useImperativeHandle(ref, () => ({
+ focusInput: () => {
+ inputRef.current?.focus();
+ },
+ clickFileInput: () => {
+ fileInputRef.current?.click();
+ },
+ }));
- // Get button position for popover anchoring
- const button = document.querySelector(
- "[data-filter-button]",
- ) as HTMLElement;
- if (button) {
- const rect = button.getBoundingClientRect();
- setAnchorPosition({
- x: rect.left + rect.width / 2,
- y: rect.top + rect.height / 2 - 12,
- });
- }
- } else {
- setIsFilterDropdownOpen(false);
- setAnchorPosition(null);
- }
- };
+ const handleFilePickerChange = (e: React.ChangeEvent) => {
+ const files = e.target.files;
+ if (files && files.length > 0) {
+ onFileSelected(files[0]);
+ } else {
+ onFileSelected(null);
+ }
+ };
- const handleFilterSelect = (filter: KnowledgeFilterData | null) => {
- onFilterSelect(filter);
+ const onAtClick = () => {
+ if (!isFilterDropdownOpen) {
+ setIsFilterDropdownOpen(true);
+ setFilterSearchTerm("");
+ setSelectedFilterIndex(0);
- // Remove the @searchTerm from the input
- const words = input.split(" ");
- const lastWord = words[words.length - 1];
+ // Get button position for popover anchoring
+ const button = document.querySelector(
+ "[data-filter-button]",
+ ) as HTMLElement;
+ if (button) {
+ const rect = button.getBoundingClientRect();
+ setAnchorPosition({
+ x: rect.left + rect.width / 2,
+ y: rect.top + rect.height / 2 - 12,
+ });
+ }
+ } else {
+ setIsFilterDropdownOpen(false);
+ setAnchorPosition(null);
+ }
+ };
- if (lastWord.startsWith("@")) {
- // Remove the @search term
- words.pop();
- onChange(words.join(" ") + (words.length > 0 ? " " : ""));
- }
+ const handleFilterSelect = (filter: KnowledgeFilterData | null) => {
+ onFilterSelect(filter);
- setIsFilterDropdownOpen(false);
- setFilterSearchTerm("");
- setSelectedFilterIndex(0);
- };
+ // Remove the @searchTerm from the input
+ const words = input.split(" ");
+ const lastWord = words[words.length - 1];
- const handleChange = (e: React.ChangeEvent) => {
- const newValue = e.target.value;
- onChange(newValue); // Call parent's onChange with the string value
+ if (lastWord.startsWith("@")) {
+ // Remove the @search term
+ words.pop();
+ onChange(words.join(" ") + (words.length > 0 ? " " : ""));
+ }
- // Find if there's an @ at the start of the last word
- const words = newValue.split(" ");
- const lastWord = words[words.length - 1];
+ setIsFilterDropdownOpen(false);
+ setFilterSearchTerm("");
+ setSelectedFilterIndex(0);
+ };
- if (lastWord.startsWith("@")) {
- const searchTerm = lastWord.slice(1); // Remove the @
- setFilterSearchTerm(searchTerm);
- setSelectedFilterIndex(0);
+ const handleChange = (e: React.ChangeEvent) => {
+ const newValue = e.target.value;
+ onChange(newValue); // Call parent's onChange with the string value
- // Only set anchor position when @ is first detected (search term is empty)
- if (searchTerm === "") {
- const getCursorPosition = (textarea: HTMLTextAreaElement) => {
- // Create a hidden div with the same styles as the textarea
- const div = document.createElement("div");
- const computedStyle = getComputedStyle(textarea);
+ // Find if there's an @ at the start of the last word
+ const words = newValue.split(" ");
+ const lastWord = words[words.length - 1];
- // Copy all computed styles to the hidden div
- for (const style of computedStyle) {
- (div.style as unknown as Record)[style] =
- computedStyle.getPropertyValue(style);
- }
+ if (lastWord.startsWith("@")) {
+ const searchTerm = lastWord.slice(1); // Remove the @
+ setFilterSearchTerm(searchTerm);
+ setSelectedFilterIndex(0);
- // Set the div to be hidden but not un-rendered
- div.style.position = "absolute";
- div.style.visibility = "hidden";
- div.style.whiteSpace = "pre-wrap";
- div.style.wordWrap = "break-word";
- div.style.overflow = "hidden";
- div.style.height = "auto";
- div.style.width = `${textarea.getBoundingClientRect().width}px`;
+ // Only set anchor position when @ is first detected (search term is empty)
+ if (searchTerm === "") {
+ const getCursorPosition = (textarea: HTMLTextAreaElement) => {
+ // Create a hidden div with the same styles as the textarea
+ const div = document.createElement("div");
+ const computedStyle = getComputedStyle(textarea);
- // Get the text up to the cursor position
- const cursorPos = textarea.selectionStart || 0;
- const textBeforeCursor = textarea.value.substring(0, cursorPos);
+ // Copy all computed styles to the hidden div
+ for (const style of computedStyle) {
+ (div.style as unknown as Record)[style] =
+ computedStyle.getPropertyValue(style);
+ }
- // Add the text before cursor
- div.textContent = textBeforeCursor;
+ // Set the div to be hidden but not un-rendered
+ div.style.position = "absolute";
+ div.style.visibility = "hidden";
+ div.style.whiteSpace = "pre-wrap";
+ div.style.wordWrap = "break-word";
+ div.style.overflow = "hidden";
+ div.style.height = "auto";
+ div.style.width = `${textarea.getBoundingClientRect().width}px`;
- // Create a span to mark the end position
- const span = document.createElement("span");
- span.textContent = "|"; // Cursor marker
- div.appendChild(span);
+ // Get the text up to the cursor position
+ const cursorPos = textarea.selectionStart || 0;
+ const textBeforeCursor = textarea.value.substring(0, cursorPos);
- // Add the text after cursor to handle word wrapping
- const textAfterCursor = textarea.value.substring(cursorPos);
- div.appendChild(document.createTextNode(textAfterCursor));
+ // Add the text before cursor
+ div.textContent = textBeforeCursor;
- // Add the div to the document temporarily
- document.body.appendChild(div);
+ // Create a span to mark the end position
+ const span = document.createElement("span");
+ span.textContent = "|"; // Cursor marker
+ div.appendChild(span);
- // Get positions
- const inputRect = textarea.getBoundingClientRect();
- const divRect = div.getBoundingClientRect();
- const spanRect = span.getBoundingClientRect();
+ // Add the text after cursor to handle word wrapping
+ const textAfterCursor = textarea.value.substring(cursorPos);
+ div.appendChild(document.createTextNode(textAfterCursor));
- // Calculate the cursor position relative to the input
- const x = inputRect.left + (spanRect.left - divRect.left);
- const y = inputRect.top + (spanRect.top - divRect.top);
+ // Add the div to the document temporarily
+ document.body.appendChild(div);
- // Clean up
- document.body.removeChild(div);
+ // Get positions
+ const inputRect = textarea.getBoundingClientRect();
+ const divRect = div.getBoundingClientRect();
+ const spanRect = span.getBoundingClientRect();
- return { x, y };
- };
+ // Calculate the cursor position relative to the input
+ const x = inputRect.left + (spanRect.left - divRect.left);
+ const y = inputRect.top + (spanRect.top - divRect.top);
- const pos = getCursorPosition(e.target);
- setAnchorPosition(pos);
- }
+ // Clean up
+ document.body.removeChild(div);
- if (!isFilterDropdownOpen) {
- setIsFilterDropdownOpen(true);
- }
- } else if (isFilterDropdownOpen) {
- // Close dropdown if @ is no longer present
- setIsFilterDropdownOpen(false);
- setFilterSearchTerm("");
- }
- };
+ return { x, y };
+ };
- const handleKeyDown = (e: React.KeyboardEvent) => {
- if (isFilterDropdownOpen) {
- if (e.key === "Escape") {
- e.preventDefault();
- setIsFilterDropdownOpen(false);
- setFilterSearchTerm("");
- setSelectedFilterIndex(0);
- inputRef.current?.focus();
- return;
- }
+ const pos = getCursorPosition(e.target);
+ setAnchorPosition(pos);
+ }
- if (e.key === "ArrowDown") {
- e.preventDefault();
- setSelectedFilterIndex((prev) =>
- prev < filteredFilters.length - 1 ? prev + 1 : 0,
- );
- return;
- }
+ if (!isFilterDropdownOpen) {
+ setIsFilterDropdownOpen(true);
+ }
+ } else if (isFilterDropdownOpen) {
+ // Close dropdown if @ is no longer present
+ setIsFilterDropdownOpen(false);
+ setFilterSearchTerm("");
+ }
+ };
- if (e.key === "ArrowUp") {
- e.preventDefault();
- setSelectedFilterIndex((prev) =>
- prev > 0 ? prev - 1 : filteredFilters.length - 1,
- );
- return;
- }
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (isFilterDropdownOpen) {
+ if (e.key === "Escape") {
+ e.preventDefault();
+ setIsFilterDropdownOpen(false);
+ setFilterSearchTerm("");
+ setSelectedFilterIndex(0);
+ inputRef.current?.focus();
+ return;
+ }
- if (e.key === "Enter") {
- // Check if we're at the end of an @ mention
- const cursorPos = e.currentTarget.selectionStart || 0;
- const textBeforeCursor = input.slice(0, cursorPos);
- const words = textBeforeCursor.split(" ");
- const lastWord = words[words.length - 1];
+ if (e.key === "ArrowDown") {
+ e.preventDefault();
+ setSelectedFilterIndex((prev) =>
+ prev < filteredFilters.length - 1 ? prev + 1 : 0,
+ );
+ return;
+ }
- if (
- lastWord.startsWith("@") &&
- filteredFilters[selectedFilterIndex]
- ) {
- e.preventDefault();
- handleFilterSelect(filteredFilters[selectedFilterIndex]);
- return;
- }
- }
+ if (e.key === "ArrowUp") {
+ e.preventDefault();
+ setSelectedFilterIndex((prev) =>
+ prev > 0 ? prev - 1 : filteredFilters.length - 1,
+ );
+ return;
+ }
- if (e.key === " ") {
- // Select filter on space if we're typing an @ mention
- const cursorPos = e.currentTarget.selectionStart || 0;
- const textBeforeCursor = input.slice(0, cursorPos);
- const words = textBeforeCursor.split(" ");
- const lastWord = words[words.length - 1];
+ if (e.key === "Enter") {
+ // Check if we're at the end of an @ mention
+ const cursorPos = e.currentTarget.selectionStart || 0;
+ const textBeforeCursor = input.slice(0, cursorPos);
+ const words = textBeforeCursor.split(" ");
+ const lastWord = words[words.length - 1];
- if (
- lastWord.startsWith("@") &&
- filteredFilters[selectedFilterIndex]
- ) {
- e.preventDefault();
- handleFilterSelect(filteredFilters[selectedFilterIndex]);
- return;
- }
- }
- }
+ if (
+ lastWord.startsWith("@") &&
+ filteredFilters[selectedFilterIndex]
+ ) {
+ e.preventDefault();
+ handleFilterSelect(filteredFilters[selectedFilterIndex]);
+ return;
+ }
+ }
- // Pass through to parent onKeyDown for other key handling
- onKeyDown(e);
- };
+ if (e.key === " ") {
+ // Select filter on space if we're typing an @ mention
+ const cursorPos = e.currentTarget.selectionStart || 0;
+ const textBeforeCursor = input.slice(0, cursorPos);
+ const words = textBeforeCursor.split(" ");
+ const lastWord = words[words.length - 1];
- return (
-