Merge branch 'main' into onboarding-fqs

This commit is contained in:
Sebastián Estévez 2025-12-02 13:15:31 -05:00 committed by GitHub
commit 48d5e7c45e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1840 additions and 641 deletions

View file

@ -101,7 +101,7 @@ services:
langflow:
volumes:
- ./flows:/app/flows:U,z
image: langflowai/openrag-langflow:${LANGFLOW_VERSION:-latest}
image: langflowai/openrag-langflow:${OPENRAG_VERSION:-latest}
build:
context: .
dockerfile: Dockerfile.langflow

View file

@ -0,0 +1,24 @@
<details>
<summary>About the OpenSearch Ingestion flow</summary>
When you upload documents locally or with OAuth connectors, the **OpenSearch Ingestion** flow runs in the background.
By default, this flow uses Docling Serve to import and process documents.
Like all [OpenRAG flows](/agents), you can [inspect the flow in Langflow](/agents#inspect-and-modify-flows), and you can customize it if you want to change the knowledge ingestion settings.
The **OpenSearch Ingestion** flow is comprised of several components that work together to process and store documents in your knowledge base:
* [**Docling Serve** component](https://docs.langflow.org/bundles-docling#docling-serve): Ingests files and processes them by connecting to OpenRAG's local Docling Serve service. The output is `DoclingDocument` data that contains the extracted text and metadata from the documents.
* [**Export DoclingDocument** component](https://docs.langflow.org/bundles-docling#export-doclingdocument): Exports processed `DoclingDocument` data to Markdown format with image placeholders. This conversion standardizes the document data in preparation for further processing.
* [**DataFrame Operations** component](https://docs.langflow.org/components-processing#dataframe-operations): Three of these components run sequentially to add metadata to the document data: `filename`, `file_size`, and `mimetype`.
* [**Split Text** component](https://docs.langflow.org/components-processing#split-text): Splits the processed text into chunks, based on the configured [chunk size and overlap settings](/knowledge#knowledge-ingestion-settings).
* **Secret Input** component: If needed, four of these components securely fetch the [OAuth authentication](/knowledge#auth) configuration variables: `CONNECTOR_TYPE`, `OWNER`, `OWNER_EMAIL`, and `OWNER_NAME`.
* **Create Data** component: Combines the authentication credentials from the **Secret Input** components into a structured data object that is associated with the document embeddings.
* [**Embedding Model** component](https://docs.langflow.org/components-embedding-models): Generates vector embeddings using your selected [embedding model](/knowledge#set-the-embedding-model-and-dimensions).
* [**OpenSearch** component](https://docs.langflow.org/bundles-elastic#opensearch): Stores the processed documents and their embeddings in a `documents` index of your OpenRAG [OpenSearch knowledge base](/knowledge).
The default address for the OpenSearch instance is `https://opensearch:9200`. To change this address, edit the `OPENSEARCH_PORT` [environment variable](/reference/configuration#opensearch-settings).
The default authentication method is JSON Web Token (JWT) authentication. If you [edit the flow](/agents#inspect-and-modify-flows), you can select `basic` auth mode, which uses the `OPENSEARCH_USERNAME` and `OPENSEARCH_PASSWORD` [environment variables](/reference/configuration#opensearch-settings) for authentication instead of JWT.
</details>

View file

@ -0,0 +1,114 @@
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
1. Open the **OpenRAG OpenSearch Agent** flow in the Langflow visual editor: From the **Chat** window, click <Icon name="Settings2" aria-hidden="true"/> **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.
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 <Icon name="Plus" aria-hidden="true"/> **Add New**.
3. Name your key, and then click **Create API Key**.
4. Copy the API key and store it securely.
5. Exit the Langflow **Settings** page to return to the visual editor.
3. Click **Share**, and then select **API access** to get pregenerated code snippets that call the Langflow API and run the flow.
These code snippets construct API requests with your Langflow server URL (`LANGFLOW_SERVER_ADDRESS`), the flow to run (`FLOW_ID`), required headers (`LANGFLOW_API_KEY`, `Content-Type`), and a payload containing the required inputs to run the flow, including a default chat input message.
In production, you would modify the inputs to suit your application logic. For example, you could replace the default chat input message with dynamic user input.
<Tabs>
<TabItem value="python" label="Python">
```python
import requests
import os
import uuid
api_key = 'LANGFLOW_API_KEY'
url = "http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID" # The complete API endpoint URL for this flow
# Request payload configuration
payload = {
"output_type": "chat",
"input_type": "chat",
"input_value": "hello world!"
}
payload["session_id"] = str(uuid.uuid4())
headers = {"x-api-key": api_key}
try:
# Send API request
response = requests.request("POST", url, json=payload, headers=headers)
response.raise_for_status() # Raise exception for bad status codes
# Print response
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error making API request: {e}")
except ValueError as e:
print(f"Error parsing response: {e}")
```
</TabItem>
<TabItem value="typescript" label="TypeScript">
```typescript
const crypto = require('crypto');
const apiKey = 'LANGFLOW_API_KEY';
const payload = {
"output_type": "chat",
"input_type": "chat",
"input_value": "hello world!"
};
payload.session_id = crypto.randomUUID();
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
"x-api-key": apiKey
},
body: JSON.stringify(payload)
};
fetch('http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID', options)
.then(response => response.json())
.then(response => console.warn(response))
.catch(err => console.error(err));
```
</TabItem>
<TabItem value="curl" label="curl">
```bash
curl --request POST \
--url 'http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID?stream=false' \
--header 'Content-Type: application/json' \
--header "x-api-key: LANGFLOW_API_KEY" \
--data '{
"output_type": "chat",
"input_type": "chat",
"input_value": "hello world!"
}'
```
</TabItem>
</Tabs>
4. Copy your preferred snippet, and then run it:
* **Python**: Paste the snippet into a `.py` file, save it, and then run it with `python filename.py`.
* **TypeScript**: Paste the snippet into a `.ts` file, save it, and then run it with `ts-node filename.ts`.
* **curl**: Paste and run snippet directly in your terminal.
If the request is successful, the response includes many details about the flow run, including the session ID, inputs, outputs, components, durations, and more.
In production, you won't pass the raw response to the user in its entirety.
Instead, you extract and reformat relevant fields for different use cases, as demonstrated in the [Langflow quickstart](https://docs.langflow.org/quickstart#extract-data-from-the-response).
For example, you could pass the chat output text to a front-end user-facing application, and store specific fields in logs and backend data stores for monitoring, chat history, or analytics.
You could also pass the output from one flow as input to another flow.

View file

@ -1,5 +0,0 @@
import Icon from "@site/src/components/icon/icon";
All flows included with OpenRAG are designed to be modular, performant, and provider-agnostic.
To modify a flow, click <Icon name="Settings2" aria-hidden="true"/> **Settings**, and click **Edit in Langflow**.
OpenRAG's visual editor is based on the [Langflow visual editor](https://docs.langflow.org/concepts-overview), so you can edit your flows to match your specific use case.

View file

@ -1,28 +1,28 @@
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';
import PartialOllama from '@site/docs/_partial-ollama.mdx';
## Application onboarding
## Application onboarding
The first time you start OpenRAG, whether using the TUI or a `.env` file, you must complete application onboarding.
The first time you start OpenRAG, regardless of how you installed it, you must complete application onboarding.
:::warning
Most values from onboarding can be changed later in the OpenRAG **Settings** page, but there are important restrictions.
The **language model provider** and **embeddings model provider** can only be selected at onboarding.
To change your provider selection later, you must [reinstall OpenRAG](/install#reinstall).
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).
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.
:::
Additionally, you can set multiple embedding models.
Choose one LLM provider and complete these steps:
You only need to complete onboarding for your preferred providers.
<Tabs groupId="Provider">
<TabItem value="Anthropic" label="Anthropic" default>
:::info
Anthropic does not provide embedding models. If you select Anthropic for your language model, you must then select a different provider for embeddings.
Anthropic doesn't provide embedding models. If you select Anthropic for your language model, you must select a different provider for embeddings.
:::
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**.
@ -34,6 +34,7 @@ Choose one LLM provider and complete these steps:
</TabItem>
<TabItem value="OpenAI" label="OpenAI">
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**.
@ -45,6 +46,7 @@ Choose one LLM provider and complete these steps:
</TabItem>
<TabItem value="IBM watsonx.ai" label="IBM watsonx.ai">
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**.
@ -56,9 +58,11 @@ Choose one LLM provider and complete these steps:
</TabItem>
<TabItem value="Ollama" label="Ollama">
:::tip
Ollama is not included with OpenRAG. To install Ollama, see the [Ollama documentation](https://docs.ollama.com/).
:::
:::info
Ollama isn't installed with OpenRAG. To install Ollama, see the [Ollama documentation](https://docs.ollama.com/).
:::
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.
@ -70,5 +74,6 @@ Choose one LLM provider and complete these steps:
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).
</TabItem>
</Tabs>

View file

@ -0,0 +1,5 @@
import Icon from "@site/src/components/icon/icon";
When using the OpenRAG **Chat**, click <Icon name="Plus" aria-hidden="true"/> in the chat input field to upload a file to the current chat session.
Files added this way are processed and made available to the agent for the current conversation only.
These files aren't stored in the knowledge base permanently.

View file

@ -1,66 +1,74 @@
---
title: Langflow in OpenRAG
title: Use Langflow in OpenRAG
slug: /agents
---
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialModifyFlows from '@site/docs/_partial-modify-flows.mdx';
OpenRAG leverages Langflow's Agent component to power the OpenRAG OpenSearch Agent flow.
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.
[Flows](https://docs.langflow.org/concepts-overview) in Langflow are functional representations of application workflows, with multiple [component](https://docs.langflow.org/concepts-components) nodes connected as single steps in a workflow.
OpenRAG includes several built-in flows:
In the OpenRAG OpenSearch Agent flow, components like the Langflow [**Agent** component](https://docs.langflow.org/agents) and [**OpenSearch** component](https://docs.langflow.org/bundles-elastic#opensearch) are connected to intelligently chat with your knowledge by embedding your query, comparing it the vector database embeddings, and generating a response with the LLM.
* The [**OpenRAG OpenSearch Agent** flow](/chat#flow) powers the **Chat** feature in OpenRAG.
* The [**OpenSearch Ingestion** and **OpenSearch URL Ingestion** flows](/ingestion) process documents and web content for storage in your OpenSearch knowledge base.
* The [**OpenRAG OpenSearch Nudges** flow](/chat#nudges) provides optional contextual suggestions in the OpenRAG **Chat**.
![OpenRAG Open Search Agent Flow](/img/opensearch-agent-flow.png)
You can customize these flows and create your own flows using OpenRAG's embedded Langflow visual editor.
The Agent component shines here in its ability to make decisions on not only what query should be sent, but when a query is necessary to solve the problem at hand.
## Inspect and modify flows {#inspect-and-modify-flows}
<details closed>
<summary>How do agents work?</summary>
All OpenRAG flows are designed to be modular, performant, and provider-agnostic.
Agents extend Large Language Models (LLMs) by integrating tools, which are functions that provide additional context and enable autonomous task execution. These integrations make agents more specialized and powerful than standalone LLMs.
To modify a flow in OpenRAG, click <Icon name="Settings2" aria-hidden="true"/> **Settings**.
From here, you can quickly edit commonly used parameters, such as the **Language model** and **Agent Instructions**.
To further explore and edit the flow, click **Edit in Langflow** to launch the embedded [Langflow visual editor](https://docs.langflow.org/concepts-overview) where you can fully [customize the flow](https://docs.langflow.org/concepts-flows) to suit your use case.
Whereas an LLM might generate acceptable, inert responses to general queries and tasks, an agent can leverage the integrated context and tools to provide more relevant responses and even take action. For example, you might create an agent that can access your company's documentation, repositories, and other resources to help your team with tasks that require knowledge of your specific products, customers, and code.
For example, to view and edit the built-in **Chat** flow (the **OpenRAG OpenSearch Agent** flow), do the following:
Agents use LLMs as a reasoning engine to process input, determine which actions to take to address the query, and then generate a response. The response could be a typical text-based LLM response, or it could involve an action, like editing a file, running a script, or calling an external API.
1. In OpenRAG, click <Icon name="MessageSquare" aria-hidden="true"/> **Chat**.
In an agentic context, tools are functions that the agent can run to perform tasks or access external resources. A function is wrapped as a Tool object with a common interface that the agent understands. Agents become aware of tools through tool registration, which is when the agent is provided a list of available tools typically at agent initialization. The Tool object's description tells the agent what the tool can do so that it can decide whether the tool is appropriate for a given request.
2. Click <Icon name="Settings2" aria-hidden="true"/> **Settings**, and then click **Edit in Langflow** to launch the Langflow visual editor in a new browser window.
</details>
If prompted to acknowledge that you are entering Langflow, click **Proceed**.
## Use the OpenRAG OpenSearch Agent flow {#flow}
If Langflow requests login information, enter the `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` from the `.env` file in your OpenRAG installation directory.
If you've chatted with your knowledge in OpenRAG, you've already experienced the OpenRAG OpenSearch Agent chat flow.
To switch OpenRAG over to the [Langflow visual editor](https://docs.langflow.org/concepts-overview) and view the OpenRAG OpenSearch Agentflow, click <Icon name="Settings2" aria-hidden="true"/> **Settings**, and then click **Edit in Langflow**.
This flow contains eight components connected together to chat with your data:
![OpenRAG OpenSearch Agent flow](/img/opensearch-agent-flow.png)
* The [**Agent** component](https://docs.langflow.org/agents) orchestrates the entire flow by deciding when to search the knowledge base, how to formulate search queries, and how to combine retrieved information with the user's question to generate a comprehensive response.
The **Agent** behaves according to the prompt in the **Agent Instructions** field.
* The [**Chat Input** component](https://docs.langflow.org/components-io) is connected to the Agent component's Input port. This allows to flow to be triggered by an incoming prompt from a user or application.
* The [**OpenSearch** component](https://docs.langflow.org/bundles-elastic#opensearch) is connected to the Agent component's Tools port. The agent might not use this database for every request; the agent only uses this connection if it decides the knowledge can help respond to the prompt.
* The [**Language Model** component](https://docs.langflow.org/components-models) is connected to the Agent component's Language Model port. The agent uses the connected LLM to reason through the request sent through Chat Input.
* The [**Embedding Model** component](https://docs.langflow.org/components-embedding-models) is connected to the OpenSearch component's Embedding port. This component converts text queries into vector representations that are compared with document embeddings stored in OpenSearch for semantic similarity matching. This gives your Agent's queries context.
* The [**Text Input** component](https://docs.langflow.org/components-io) is populated with the global variable `OPENRAG-QUERY-FILTER`.
This filter is the [Knowledge filter](/knowledge#create-knowledge-filters), and filters which knowledge sources to search through.
* The **Agent** component's Output port is connected to the [**Chat Output** component](https://docs.langflow.org/components-io), which returns the final response to the user or application.
* An [**MCP Tools** component](https://docs.langflow.org/mcp-client) is connected to the Agent's **Tools** port. This component calls the [OpenSearch URL Ingestion flow](/ingestion#url-flow), which Langflow uses as an MCP server to fetch content from URLs and store in OpenSearch.
3. Modify the flow as desired, and then press <kbd>Command</kbd>+<kbd>S</kbd> (<kbd>Ctrl</kbd>+<kbd>S</kbd>) to save your changes.
<PartialModifyFlows />
You can close the Langflow browser window, or leave it open if you want to continue experimenting with the flow editor.
For an example of changing out the agent's language model in OpenRAG, see the [Quickstart](/quickstart#change-components).
:::tip
If you modify the built-in **Chat** flow, make sure you click <Icon name="Plus" aria-hidden="true"/> in the **Conversations** tab to start a new conversation. This ensures that the chat doesn't persist any context from the previous conversation with the original flow settings.
:::
To restore the flow to its initial state, in OpenRAG, click <Icon name="Settings2" aria-hidden="true"/> **Settings**, and then click **Restore Flow**.
OpenRAG warns you that this discards all custom settings. Click **Restore** to restore the flow.
### Revert a built-in flow to its original configuration {#revert-a-built-in-flow-to-its-original-configuration}
## Additional Langflow functionality
After you edit a built-in flow, you can click **Restore flow** on the **Settings** page to revert the flow to its original state when you first installed OpenRAG.
This is a destructive action that discards all customizations to the flow.
Langflow includes features beyond Agents to help you integrate OpenRAG into your application, and all Langflow features are included in OpenRAG.
## Build custom flows and use other Langflow functionality
* Langflow can serve your flows as an [MCP server](https://docs.langflow.org/mcp-server), or consume other MCP servers as an [MCP client](https://docs.langflow.org/mcp-client). Get started with the [MCP tutorial](https://docs.langflow.org/mcp-tutorial).
In addition to OpenRAG's built-in flows, all Langflow features are available through OpenRAG, including the ability to [create your own flows](https://docs.langflow.org/concepts-flows) and popular extensibility features such as the following:
* If you don't see the component you need, extend Langflow's functionality by creating [custom Python components](https://docs.langflow.org/components-custom-components).
* [Create custom components](https://docs.langflow.org/components-custom-components).
* Integrate with many third-party services through [bundles](https://docs.langflow.org/components-bundle-components).
* Use [MCP clients](https://docs.langflow.org/mcp-client) and [MCP servers](https://docs.langflow.org/mcp-server), and serve flows as MCP tools for your agentic flows.
* Langflow offers component [bundles](https://docs.langflow.org/components-bundle-components) to integrate with many popular vector stores, AI/ML providers, and search APIs.
Explore the [Langflow documentation](https://docs.langflow.org/) to learn more about the Langflow platform, features, and visual editor.
## Set the Langflow version
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:
* 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.
* Components might break, including components in OpenRAG's built-in flows.
* Default settings and behaviors might change causing unexpected results when OpenRAG expects a newer default.

View file

@ -0,0 +1,94 @@
---
title: Chat in OpenRAG
slug: /chat
---
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialIntegrateChat from '@site/docs/_partial-integrate-chat.mdx';
import PartialTempKnowledge from '@site/docs/_partial-temp-knowledge.mdx';
After you [upload documents to your knowledge base](/ingestion), you can use the OpenRAG <Icon name="MessageSquare" aria-hidden="true"/> **Chat** feature to interact with your knowledge through natural language queries.
:::tip
Try chatting, uploading documents, and modifying chat settings in the [quickstart](/quickstart).
:::
## OpenRAG OpenSearch Agent flow {#flow}
When you use the OpenRAG **Chat**, the **OpenRAG OpenSearch Agent** [flow](/agents) runs in the background to retrieve relevant information from your knowledge base and generate a response.
If you [inspect the flow in Langflow](/agents#inspect-and-modify-flows), you'll see that it is comprised of eight components that work together to ingest chat messages, retrieve relevant information from your knowledge base, and then generate responses.
![OpenRAG Open Search Agent Flow](/img/opensearch-agent-flow.png)
* [**Chat Input** component](https://docs.langflow.org/components-io): This component starts the flow when it receives a chat message. It is connected to the **Agent** component's **Input** port.
When you use the OpenRAG **Chat**, your chat messages are passed to the **Chat Input** component, which then sends them to the **Agent** component for processing.
* [**Agent** component](https://docs.langflow.org/agents): This component orchestrates the entire flow by processing chat messages, searching the knowledge base, and organizing the retrieved information into a cohesive response.
The agent's general behavior is defined by the prompt in the **Agent Instructions** field and the model connected to the **Language Model** port.
One or more specialized tools can be attached to the **Tools** port to extend the agent's capabilities. In this case, there are two tools: **MCP Tools** and **OpenSearch**.
The **Agent** component is the star of this flow because it powers decision making, tool calling, and an LLM-driven conversational experience.
<details>
<summary>How do agents work?</summary>
Agents extend Large Language Models (LLMs) by integrating tools, which are functions that provide additional context and enable autonomous task execution. These integrations make agents more specialized and powerful than standalone LLMs.
Whereas an LLM might generate acceptable, inert responses to general queries and tasks, an agent can leverage the integrated context and tools to provide more relevant responses and even take action. For example, you might create an agent that can access your company's documentation, repositories, and other resources to help your team with tasks that require knowledge of your specific products, customers, and code.
Agents use LLMs as a reasoning engine to process input, determine which actions to take to address the query, and then generate a response. The response could be a typical text-based LLM response, or it could involve an action, like editing a file, running a script, or calling an external API.
In an agentic context, tools are functions that the agent can run to perform tasks or access external resources. A function is wrapped as a Tool object with a common interface that the agent understands. Agents become aware of tools through tool registration, which is when the agent is provided a list of available tools typically at agent initialization. The Tool object's description tells the agent what the tool can do so that it can decide whether the tool is appropriate for a given request.
</details>
* [**Language Model** component](https://docs.langflow.org/components-models): Connected to the **Agent** component's **Language Model** port, this component provides the base language model driver for the agent. The agent cannot function without a model because the model is used for general knowledge, reasoning, and generating responses.
Different models can change the style and content of the agent's responses, and some models might be better suited for certain tasks than others. If the agent doesn't seem to be handling requests well, try changing the model to see how the responses change. For example, fast models might be good for simple queries, but they might not have the depth of reasoning for complex, multi-faceted queries.
* [**MCP Tools** component](https://docs.langflow.org/mcp-client): Connected to the **Agent** component's **Tools** port, this component can be used to [access any Model Context Protocol (MCP) server](https://docs.langflow.org/mcp-server) and the MCP tools provided by that server. In this case, your OpenRAG Langflow instance's [**Starter Project**](https://docs.langflow.org/concepts-flows#projects) is the MCP server, and the [**OpenSearch URL Ingestion** flow](/ingestion#url-flow) is the MCP tool.
This flow fetches content from URLs, and then stores the content in your OpenRAG OpenSearch knowledge base. By serving this flow as an MCP tool, the agent can selectively call this tool if a URL is detected in the chat input.
* [**OpenSearch** component](https://docs.langflow.org/bundles-elastic#opensearch): Connected to the **Agent** component's **Tools** port, this component lets the agent search your [OpenRAG OpenSearch knowledge base](/knowledge). The agent might not use this database for every request; the agent uses this connection only if it decides that documents in your knowledge base are relevant to your query.
* [**Embedding Model** component](https://docs.langflow.org/components-embedding-models): Connected to the **OpenSearch** component's **Embedding** port, this component generates embeddings from chat input that are used in [similarity search](https://www.ibm.com/think/topics/vector-search) to find content in your knowledge base that is relevant to the chat input. The agent uses this information to generate context-aware responses that are specialized for your data.
It is critical that the embedding model used here matches the embedding model used when you [upload documents to your knowledge base](/ingestion). Mismatched models and dimensions can degrade the quality of similarity search results causing the agent to retrieve irrelevant documents from your knowledge base.
* [**Text Input** component](https://docs.langflow.org/components-io): Connected to the **OpenSearch** component's **Search Filters** port, this component is populated with a Langflow global variable named `OPENRAG-QUERY-FILTER`. If a global or chat-level [knowledge filter](/knowledge-filters) is set, then the variable contains the filter expression, which limits the documents that the agent can access in the knowledge base.
If no knowledge filter is set, then the `OPENRAG-QUERY-FILTER` variable is empty, and the agent can access all documents in the knowledge base.
* [**Chat Output** component](https://docs.langflow.org/components-io): Connected to the **Agent** component's **Output** port, this component returns the agent's generated response as a chat message.
## Nudges {#nudges}
When you use the OpenRAG **Chat**, the **OpenRAG OpenSearch Nudges** flow runs in the background to pull additional context from your knowledge base and chat history.
Nudges appear as prompts in the chat.
Click a nudge to accept it and provide the nudge's context to the OpenRAG **Chat** agent (the **OpenRAG OpenSearch Agent** flow).
Like OpenRAG's other built-in flows, you can [inspect the flow in Langflow](/agents#inspect-and-modify-flows), and you can customize it if you want to change the nudge behavior.
## Upload documents to the chat
<PartialTempKnowledge />
## Inspect tool calls and knowledge
During the chat, you'll see information about the agent's process. For more detail, you can inspect individual tool calls. This is helpful for troubleshooting because it shows you how the agent used particular tools. For example, click <Icon name="Gear" aria-hidden="true"/> **Function Call: search_documents (tool_call)** to view the log of tool calls made by the agent to the **OpenSearch** component.
If documents in your knowledge base seem to be missing or interpreted incorrectly, see [Troubleshoot ingestion](/ingestion#troubleshoot-ingestion).
If tool calls and knowledge appear normal, but the agent's responses seem off-topic or incorrect, consider changing the agent's language model or prompt, as explained in [Inspect and modify flows](/agents#inspect-and-modify-flows).
## Integrate OpenRAG chat into an application
You can integrate OpenRAG flows into your applications using the [Langflow API](https://docs.langflow.org/api-reference-api-examples).
To simplify this integration, you can get pre-configured code snippets directly from the embedded Langflow visual editor.
The following example demonstrates how to generate and use code snippets for the **OpenRAG OpenSearch Agent** flow:
<PartialIntegrateChat />

View file

@ -1,120 +1,290 @@
---
title: Docling in OpenRAG
title: Ingest knowledge
slug: /ingestion
---
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialModifyFlows from '@site/docs/_partial-modify-flows.mdx';
import PartialTempKnowledge from '@site/docs/_partial-temp-knowledge.mdx';
import PartialIngestionFlow from '@site/docs/_partial-ingestion-flow.mdx';
OpenRAG uses [Docling](https://docling-project.github.io/docling/) for document ingestion.
More specifically, OpenRAG uses [Docling Serve](https://github.com/docling-project/docling-serve), which starts a `docling serve` process on your local machine and runs Docling ingestion through an API service.
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.
Docling ingests documents from your local machine or OAuth connectors, splits them into chunks, and stores them as separate, structured documents in the OpenSearch `documents` index.
OpenRAG can ingest knowledge from direct file uploads, URLs, and OAuth authenticated connectors.
OpenRAG chose Docling for its support for a wide variety of file formats, high performance, and advanced understanding of tables and images.
Knowledge ingestion is powered by OpenRAG's built-in knowledge ingestion flows that use Docling to process documents before storing the documents in your OpenSearch database.
During ingestion, documents are broken into smaller chunks of content that are then embedded using your selected [embedding model](/knowledge#set-the-embedding-model-and-dimensions).
Then, the chunks, embeddings, and associated metadata (which connects chunks of the same document) are stored in your OpenSearch database.
To modify OpenRAG's ingestion settings, including the Docling settings and ingestion flows, click 2" aria-hidden="true"/> **Settings**.
To modify chunking behavior and other ingestion settings, see [Knowledge ingestion settings](/knowledge#knowledge-ingestion-settings) and [Inspect and modify flows](/agents#inspect-and-modify-flows).
## Knowledge ingestion settings
## Ingest local files and folders
These settings configure the Docling ingestion parameters.
You can upload files and folders from your local machine to your knowledge base:
OpenRAG will warn you if `docling serve` is not running.
To start or stop `docling serve` or any other native services, in the TUI main menu, click **Start Native Services** or **Stop Native Services**.
1. Click <Icon name="Library" aria-hidden="true"/> **Knowledge** to view your OpenSearch knowledge base.
**Embedding model** determines which AI model is used to create vector embeddings. The default is the OpenAI `text-embedding-3-small` model.
2. Click **Add Knowledge** to add your own documents to your OpenRAG knowledge base.
**Chunk size** determines how large each text chunk is in number of characters.
Larger chunks yield more context per chunk, but can include irrelevant information. Smaller chunks yield more precise semantic search, but can lack context.
The default value of `1000` characters provides a good starting point that balances these considerations.
3. To upload one file, click <Icon name="File" aria-hidden="true"/> **File**. To upload all documents in a folder, click <Icon name="Folder" aria-hidden="true"/> **Folder**.
**Chunk overlap** controls the number of characters that overlap over chunk boundaries.
Use larger overlap values for documents where context is most important, and use smaller overlap values for simpler documents, or when optimization is most important.
The default value of 200 characters of overlap with a chunk size of 1000 (20% overlap) is suitable for general use cases. Decrease the overlap to 10% for a more efficient pipeline, or increase to 40% for more complex documents.
The default path is the `./documents` subdirectory in your OpenRAG installation directory.
To change this path, see [Set the local documents path](/knowledge#set-the-local-documents-path).
**Table Structure** enables Docling's [`DocumentConverter`](https://docling-project.github.io/docling/reference/document_converter/) tool for parsing tables. Instead of treating tables as plain text, tables are output as structured table data with preserved relationships and metadata. **Table Structure** is enabled by default.
The selected files are processed in the background through the **OpenSearch Ingestion** flow.
**OCR** enables or disabled OCR processing when extracting text from images and scanned documents.
OCR is disabled by default. This setting is best suited for processing text-based documents as quickly as possible with Docling's [`DocumentConverter`](https://docling-project.github.io/docling/reference/document_converter/). Images are ignored and not processed.
<PartialIngestionFlow />
Enable OCR when you are processing documents containing images with text that requires extraction, or for scanned documents. Enabling OCR can slow ingestion performance.
You can [monitor ingestion](#monitor-ingestion) to see the progress of the uploads and check for failed uploads.
If OpenRAG detects that the local machine is running on macOS, OpenRAG uses the [ocrmac](https://www.piwheels.org/project/ocrmac/) OCR engine. Other platforms use [easyocr](https://www.jaided.ai/easyocr/).
## Ingest local files temporarily
**Picture descriptions** adds image descriptions generated by the [SmolVLM-256M-Instruct](https://huggingface.co/HuggingFaceTB/SmolVLM-Instruct) model to OCR processing. Enabling picture descriptions can slow ingestion performance.
<PartialTempKnowledge />
## Knowledge ingestion flows
## Ingest files with OAuth connectors {#oauth-ingestion}
[Flows](https://docs.langflow.org/concepts-overview) in Langflow are functional representations of application workflows, with multiple [component](https://docs.langflow.org/concepts-components) nodes connected as single steps in a workflow.
OpenRAG can use OAuth authenticated connectors to ingest documents from the following external services:
The **OpenSearch Ingestion** flow is the default knowledge ingestion flow in OpenRAG: when you **Add Knowledge** in OpenRAG, you run the OpenSearch Ingestion flow in the background. The flow ingests documents using **Docling Serve** to import and process documents.
* AWS S3
* Google Drive
* Microsoft OneDrive
* Microsoft Sharepoint
This flow contains ten components connected together to process and store documents in your knowledge base.
These connectors enable seamless ingestion of files from cloud storage to your OpenRAG knowledge base.
* The [**Docling Serve** component](https://docs.langflow.org/bundles-docling) processes input documents by connecting to your instance of Docling Serve.
* The [**Export DoclingDocument** component](https://docs.langflow.org/components-docling) exports the processed DoclingDocument to markdown format with image export mode set to placeholder. This conversion makes the structured document data into a standardized format for further processing.
* Three [**DataFrame Operations** components](https://docs.langflow.org/components-processing#dataframe-operations) sequentially add metadata columns to the document data of `filename`, `file_size`, and `mimetype`.
* The [**Split Text** component](https://docs.langflow.org/components-processing#split-text) splits the processed text into chunks with a chunk size of 1000 characters and an overlap of 200 characters.
* Four **Secret Input** components provide secure access to configuration variables: `CONNECTOR_TYPE`, `OWNER`, `OWNER_EMAIL`, and `OWNER_NAME`. These are runtime variables populated from OAuth login.
* The **Create Data** component combines the secret inputs into a structured data object that will be associated with the document embeddings.
* The [**Embedding Model** component](https://docs.langflow.org/components-embedding-models) generates vector embeddings using OpenAI's `text-embedding-3-small` model. The embedding model is selected at [Application onboarding] and cannot be changed.
* The [**OpenSearch** component](https://docs.langflow.org/bundles-elastic#opensearch) stores the processed documents and their embeddings in the `documents` index at `https://opensearch:9200`. By default, the component is authenticated with a JWT token, but you can also select `basic` auth mode, and enter your OpenSearch admin username and password.
Individual users can connect their personal cloud storage accounts to OpenRAG. Each user must separately authorize OpenRAG to access their own cloud storage. When a user connects a cloud storage service, they are redirected to authenticate with that service provider and grant OpenRAG permission to sync documents from their personal cloud storage.
<PartialModifyFlows />
### Enable OAuth connectors
### OpenSearch URL Ingestion flow {#url-flow}
Before users can connect their own cloud storage accounts, you must configure the provider's OAuth credentials in OpenRAG. Typically, this requires that you register OpenRAG as an OAuth application in your cloud provider, and then obtain the app's OAuth credentials, such as a client ID and secret key.
To enable multiple connectors, you must register an app and generate credentials for each provider.
An additional knowledge ingestion flow is included in OpenRAG, where it is used as an MCP tool by the [**Open Search Agent flow**](/agents#flow).
The agent calls this component to fetch web content, and the results are ingested into OpenSearch.
<Tabs>
<TabItem value="TUI" label="TUI Advanced Setup" default>
For more on using MCP clients in Langflow, see [MCP clients](https://docs.langflow.org/mcp-client).\
To connect additional MCP servers to the MCP client, see [Connect to MCP servers from your application](https://docs.langflow.org/mcp-tutorial).
If you use the TUI to manage your OpenRAG containers, provide OAuth credentials in the **Advanced Setup**.
## Use OpenRAG default ingestion instead of Docling serve
You can do this during [installation](/install#setup), or you can add the credentials afterwards:
If you want to use OpenRAG's built-in pipeline instead of Docling serve, set `DISABLE_INGEST_WITH_LANGFLOW=true` in [Environment variables](/reference/configuration#document-processing).
1. If OpenRAG is running, stop it: Go to [**Status**](/install#tui-container-management), and then click **Stop Services**.
The built-in pipeline still uses the Docling processor, but uses it directly without the Docling Serve API.
2. Click **Advanced Setup**, and then add the OAuth credentials for the cloud storage providers that you want to use:
For more information, see [`processors.py` in the OpenRAG repository](https://github.com/langflow-ai/openrag/blob/main/src/models/processors.py#L58).
* **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).
## Performance expectations
3. The OpenRAG 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**.
OpenRAG regenerates the [`.env`](/reference/configuration) file with the given credentials.
5. Click **Start Container Services**.
</TabItem>
<TabItem value="env" label="Docker Compose .env file">
If you [install OpenRAG with self-managed containers](/docker), set OAuth credentials in the `.env` file for Docker Compose.
You can do this during [initial set up](/docker#install-openrag-with-docker-compose), or you can add the credentials afterwards:
1. Stop your OpenRAG deployment.
<Tabs>
<TabItem value="podman" label="Podman">
```bash
podman stop --all
```
</TabItem>
<TabItem value="docker" label="Docker">
```bash
docker stop $(docker ps -q)
```
</TabItem>
</Tabs>
2. Edit the `.env` file for Docker Compose 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).
```env
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
```
* **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).
```env
GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
```
* **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).
```env
MICROSOFT_GRAPH_OAUTH_CLIENT_ID=
MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET=
```
3. Save the `.env` file.
4. Restart your OpenRAG deployment:
<Tabs>
<TabItem value="podman" label="Podman">
```bash
podman-compose up -d
```
</TabItem>
<TabItem value="docker" label="Docker">
```bash
docker-compose up -d
```
</TabItem>
</Tabs>
</TabItem>
</Tabs>
### Authenticate and ingest files from cloud storage
After you start OpenRAG with OAuth connectors enabled, each user is prompted to authenticate with the OAuth provider upon accessing your OpenRAG instance.
Individual authentication is required to access a user's cloud storage from your OpenRAG instance.
For example, if a user navigates to the default OpenRAG URL at `http://localhost:3000`, they are redirected to the OAuth provider's sign-in page.
After authenticating and granting the required permissions for OpenRAG, the user is redirected back to OpenRAG.
To ingest knowledge with an OAuth connector, do the following:
1. Click <Icon name="Library" aria-hidden="true"/> **Knowledge** to view your OpenSearch knowledge base.
2. Click **Add Knowledge**, and then select a storage provider.
3. On the **Add Cloud Knowledge** page, click **Add Files**, and then select the files and folders to ingest from the connected storage.
4. Click **Ingest Files**.
The selected files are processed in the background through the **OpenSearch Ingestion** flow.
<PartialIngestionFlow />
You can [monitor ingestion](#monitor-ingestion) to see the progress of the uploads and check for failed uploads.
## Ingest knowledge from URLs {#url-flow}
The **OpenSearch URL Ingestion** flow is used to ingest web content from URLs.
This flow isn't directly accessible from the OpenRAG user interface.
Instead, this flow is called by the [**OpenRAG OpenSearch Agent** flow](/chat#flow) as a Model Context Protocol (MCP) tool.
The agent can call this component to fetch web content from a given URL, and then ingest that content into your OpenSearch knowledge base.
Like all OpenRAG flows, you can [inspect the flow in Langflow](/agents#inspect-and-modify-flows), and you can customize it.
For more information about MCP in Langflow, see the Langflow documentation on [MCP clients](https://docs.langflow.org/mcp-client) and [MCP servers](https://docs.langflow.org/mcp-tutorial).
## Monitor ingestion
Document ingestion tasks run in the background.
In the OpenRAG user interface, a badge is shown on <Icon name="Bell" aria-hidden="true"/> **Tasks** when OpenRAG tasks are active.
Click <Icon name="Bell" aria-hidden="true"/> **Tasks** to inspect and cancel tasks:
* **Active Tasks**: All tasks that are **Pending**, **Running**, or **Processing**.
For each active task, depending on its state, you can find the task ID, start time, duration, number of files processed, and the total files enqueued for processing.
* **Pending**: The task is queued and waiting to start.
* **Running**: The task is actively processing files.
* **Processing**: The task is performing ingestion operations.
* **Failed**: Something went wrong during ingestion, or the task was manually canceled.
For troubleshooting advice, see [Troubleshoot ingestion](#troubleshoot-ingestion).
To stop an active task, click <Icon name="X" aria-hidden="true"/> **Cancel**. Canceling a task stops processing immediately and marks the task as **Failed**.
### Ingestion performance expectations
The following performance test was conducted with Docling Serve.
On a local VM with 7 vCPUs and 8 GiB RAM, OpenRAG ingested approximately 5.03 GB across 1,083 files in about 42 minutes.
This equates to approximately 2.4 documents per second.
You can generally expect equal or better performance on developer laptops and significantly faster on servers.
Throughput scales with CPU cores, memory, storage speed, and configuration choices such as embedding model, chunk size and overlap, and concurrency.
You can generally expect equal or better performance on developer laptops, and significantly faster performance on servers.
Throughput scales with CPU cores, memory, storage speed, and configuration choices, such as the embedding model, chunk size, overlap, and concurrency.
This test returned 12 errors (approximately 1.1%).
This test returned 12 error, approximately 1.1 percent of the total files ingested.
All errors were file-specific, and they didn't stop the pipeline.
Ingestion dataset:
<details>
<summary>Ingestion performance test details</summary>
* Total files: 1,083 items mounted
* Total size on disk: 5,026,474,862 bytes (approximately 5.03 GB)
* Ingestion dataset:
Hardware specifications:
* Total files: 1,083 items mounted
* Total size on disk: 5,026,474,862 bytes (approximately 5.03 GB)
* Machine: Apple M4 Pro
* Podman VM:
* Name: `podman-machine-default`
* Type: `applehv`
* vCPUs: 7
* Memory: 8 GiB
* Disk size: 100 GiB
* Hardware specifications:
Test results:
* Machine: Apple M4 Pro
* Podman VM:
* Name: podman-machine-default
* Type: applehv
* vCPUs: 7
* Memory: 8 GiB
* Disk size: 100 GiB
```text
2025-09-24T22:40:45.542190Z /app/src/main.py:231 Ingesting default documents when ready disable_langflow_ingest=False
2025-09-24T22:40:45.546385Z /app/src/main.py:270 Using Langflow ingestion pipeline for default documents file_count=1082
...
2025-09-24T23:19:44.866365Z /app/src/main.py:351 Langflow ingestion completed success_count=1070 error_count=12 total_files=1082
```
* Test results:
Elapsed time: ~42 minutes 15 seconds (2,535 seconds)
```text
2025-09-24T22:40:45.542190Z /app/src/main.py:231 Ingesting default documents when ready disable_langflow_ingest=False
2025-09-24T22:40:45.546385Z /app/src/main.py:270 Using Langflow ingestion pipeline for default documents file_count=1082
...
2025-09-24T23:19:44.866365Z /app/src/main.py:351 Langflow ingestion completed success_count=1070 error_count=12 total_files=1082
```
Throughput: ~2.4 documents/second
* Elapsed time: Approximately 42 minutes 15 seconds (2,535 seconds)
* Throughput: Approximately 2.4 documents per second
</details>
## Troubleshoot ingestion {#troubleshoot-ingestion}
If an ingestion task fails, do the following:
* Make sure you are uploading supported file types.
* Split excessively large files into smaller files before uploading.
* Remove unusual embedded content, such as videos or animations, before uploading. Although Docling can replace some non-text content with placeholders during ingestion, some embedded content might cause errors.
If the OpenRAG **Chat** doesn't seem to use your documents correctly, [browse your knowledge base](#browse-knowledge) to confirm that the documents are uploaded in full, and the chunks are correct.
If the documents are present and well-formed, check your [knowledge filters](/knowledge-filters).
If a global filter is applied, make sure the expected documents are included in the global filter.
If the global filter excludes any documents, the agent cannot access those documents unless you apply a chat-level filter or change the global filter.
If text is missing or incorrectly processed, you need to reupload the documents after modifying the ingestion parameters or the documents themselves.
For example:
* Break combined documents into separate files for better metadata context.
* Make sure scanned documents are legible enough for extraction, and enable the **OCR** option. Poorly scanned documents might require additional preparation or rescanning before ingestion.
* Adjust the **Chunk Size** and **Chunk Overlap** settings to better suit your documents. Larger chunks provide more context but can include irrelevant information, while smaller chunks yield more precise semantic search but can lack context.
For more information about modifying ingestion parameters and flows, see [Knowledge ingestion settings](/knowledge#knowledge-ingestion-settings).
## See also
* [Configure knowledge](/knowledge)
* [Filter knowledge](/knowledge-filters)
* [Chat with knowledge](/chat)
* [Inspect and modify flows](/agents#inspect-and-modify-flows)

View file

@ -0,0 +1,53 @@
---
title: Filter knowledge
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.
Each knowledge filter captures a specific subset of documents based on given a search query and filters.
Knowledge filters can be used with different OpenRAG functionality.
For example, knowledge filters can help agents access large knowledge bases efficiently by narrowing the scope of documents that you want the agent to use.
## Create a filter
To create a knowledge filter, do the following:
1. Click **Knowledge**, and then click <Icon name="Plus" aria-hidden="true"/> **Knowledge Filters**.
2. Enter a **Name** and **Description**, and then click **Create Filter**.
By default, new filters match all documents in your knowledge base.
Modify the filter to customize it.
3. To modify the filter, click <Icon name="Library" aria-hidden="true"/> **Knowledge**, and then click your new filter. You can edit the following settings:
* **Search Query**: Enter text for semantic search, such as `financial reports from Q4`.
* **Data Sources**: Select specific data sources or folders to include.
* **Document Types**: Filter by file type.
* **Owners**: Filter by the user that uploaded the documents.
* **Connectors**: Filter by [upload source](/ingestion), such as the local file system or a Google Drive OAuth connector.
* **Response Limit**: Set the maximum number of results to return from the knowledge base. The default is `10`.
* **Score Threshold**: Set the minimum relevance score for similarity search. The default score is `0`.
4. To save your changes, click **Update Filter**.
## Apply a filter {#apply-a-filter}
* **Apply a global filter**: Click <Icon name="Library" aria-hidden="true"/> **Knowledge**, and then enable the toggle next to your preferred filter. Only one filter can be the global filter. The global filter applies to all chat sessions.
* **Apply a chat filter**: In the <Icon name="MessageSquare" aria-hidden="true"/> **Chat** window, click <Icon name="Funnel" aria-hidden="true"/> **Filter**, and then select the filter to apply.
Chat filters apply to one chat session only.
## Delete a filter
1. Click <Icon name="Library" aria-hidden="true"/> **Knowledge**.
2. Click the filter that you want to delete.
3. Click **Delete Filter**.

View file

@ -1,158 +1,168 @@
---
title: OpenSearch in OpenRAG
title: Configure knowledge
slug: /knowledge
---
import Icon from "@site/src/components/icon/icon";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import PartialModifyFlows from '@site/docs/_partial-modify-flows.mdx';
OpenRAG uses [OpenSearch](https://docs.opensearch.org/latest/) for its vector-backed knowledge store.
This is a specialized database for storing and retrieving embeddings, which helps your Agent efficiently find relevant information.
OpenSearch provides powerful hybrid search capabilities with enterprise-grade security and multi-tenancy support.
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).
## Authentication and document access {#auth}
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).
OpenRAG supports two authentication modes based on how you [install OpenRAG](/install), and which mode you choose affects document access.
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.
**No-auth mode (Basic Setup)**: This mode uses a single anonymous JWT token for OpenSearch authentication, so documents uploaded to the `documents` index by one user are visible to all other users on the OpenRAG server.
Then, the [OpenRAG **Chat**](/chat) can run [similarity searches](https://www.ibm.com/think/topics/vector-search) against your OpenSearch database to retrieve relevant information and generate context-aware responses.
**OAuth mode (Advanced Setup)**: Each OpenRAG user is granted a JWT token, and each document is tagged with user ownership. Documents are filtered by user ownership, ensuring users only see documents they uploaded or have access to.
You can configure how documents are ingested and how the **Chat** interacts with your knowledge base.
## Ingest knowledge
## Browse knowledge {#browse-knowledge}
OpenRAG supports knowledge ingestion through direct file uploads and OAuth connectors.
To configure the knowledge ingestion pipeline parameters, see [Docling Ingestion](/ingestion).
The **Knowledge** page lists the documents OpenRAG has ingested into your OpenSearch database, specifically in an [OpenSearch index](https://docs.opensearch.org/latest/getting-started/intro/#index) named `documents`.
### Direct file ingestion
To explore the raw contents of your knowledge base, click <Icon name="Library" aria-hidden="true"/> **Knowledge** to get a list of all ingested documents.
Click a document to view the chunks produced from splitting the document during ingestion.
The **Knowledge Ingest** flow uses Langflow's [**File** component](https://docs.langflow.org/components-data#file) to split and embed files loaded from your local machine into the OpenSearch database.
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.
It is recommended that you keep these documents, and use [filters](/knowledge-filters) to separate them from your other knowledge.
The default path to your local folder is mounted from the `./openrag-documents` folder in your OpenRAG project directory to the `/app/openrag-documents/` directory inside the Docker container. Files added to the host or the container will be visible in both locations. To configure this location, modify the **Documents Paths** variable in either the TUI's [Advanced Setup](/install#setup) menu or in the `.env` used by Docker Compose.
## OpenSearch authentication and document access {#auth}
To load and process a single file from the mapped location, click **Add Knowledge**, and then click <Icon name="File" aria-hidden="true"/> **File**.
The file is loaded into your OpenSearch database, and appears in the Knowledge page.
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:
To load and process a directory from the mapped location, click **Add Knowledge**, and then click <Icon name="Folder" aria-hidden="true"/> **Folder**.
The files are loaded into your OpenSearch database, and appear in the Knowledge page.
* **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.
To add files directly to a chat session, click <Icon name="Plus" aria-hidden="true"/> in the chat input and select the files you want to include. Files added this way are processed and made available to the agent for the current conversation, and are not permanently added to the 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.
### Ingest files through OAuth connectors {#oauth-ingestion}
You can enable OAuth mode after installation.
For more information, see [Ingest files with OAuth connectors](/ingestion#oauth-ingestion).
OpenRAG supports Google Drive, OneDrive, and Sharepoint as OAuth connectors for seamless document synchronization.
## OpenSearch indexes
OAuth integration allows individual users to connect their personal cloud storage accounts to OpenRAG. Each user must separately authorize OpenRAG to access their own cloud storage files. When a user connects a cloud service, they are redirected to authenticate with that service provider and grant OpenRAG permission to sync documents from their personal cloud storage.
An [OpenSearch index](https://docs.opensearch.org/latest/getting-started/intro/#index) is a collection of documents in an OpenSearch database.
Before users can connect their cloud storage accounts, you must configure OAuth credentials in OpenRAG. This requires registering OpenRAG as an OAuth application with a cloud provider and obtaining client ID and secret keys for each service you want to support.
By default, all documents you upload to your OpenRAG knowledge base are stored in an index named `documents`.
To add an OAuth connector to OpenRAG, do the following.
This example uses Google OAuth.
If you wish to use another provider, add the secrets to another provider.
It is possible to change the index name by [editing the ingestion flow](/agents#inspect-and-modify-flows).
However, this can impact dependent processes, such as the [filters](/knowledge-filters) and [**Chat**](/chat) flow, that reference the `documents` index by default.
Make sure you edit other flows as needed to ensure all processes use the same index name.
<Tabs groupId="Installation type">
<TabItem value="TUI" label="TUI" default>
1. If OpenRAG is running, stop it with **Status** > **Stop Services**.
2. Click **Advanced Setup**.
3. Add the OAuth provider's client and secret key in the [Advanced Setup](/install#setup) menu.
4. Click **Save Configuration**.
The TUI generates a new `.env` file with your OAuth values.
5. Click **Start Container Services**.
</TabItem>
<TabItem value=".env" label=".env">
1. Stop the Docker deployment.
2. Add the OAuth provider's client and secret key in the `.env` file for Docker Compose.
```bash
GOOGLE_OAUTH_CLIENT_ID='YOUR_OAUTH_CLIENT_ID'
GOOGLE_OAUTH_CLIENT_SECRET='YOUR_OAUTH_CLIENT_SECRET'
```
3. Save your `.env` file.
4. Start the Docker deployment.
</TabItem>
If you encounter errors or unexpected behavior after changing the index name, you can [revert the flows to their original configuration](/agents#revert-a-built-in-flow-to-its-original-configuration), or [delete knowledge](/knowledge#delete-knowledge) to clear the existing documents from your knowledge base.
## Knowledge ingestion settings {#knowledge-ingestion-settings}
:::warning
Knowledge ingestion settings apply to documents you upload after making the changes.
Documents uploaded before changing these settings aren't reprocessed.
:::
After changing knowledge ingestion settings, you must determine if you need to reupload any documents to be consistent with the new settings.
It isn't always necessary to reupload documents after changing knowledge ingestion settings.
For example, it is typical to upload some documents with OCR enabled and others without OCR enabled.
If needed, you can use [filters](/knowledge-filters) to separate documents that you uploaded with different settings, such as different embedding models.
### 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).
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.
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 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).
This will automatically update all relevant [OpenRAG flows](/agents) to use the new embedding model configuration.
### Set Docling parameters
OpenRAG uses [Docling](https://docling-project.github.io/docling/) for document ingestion because it supports many file formats, processes tables and images well, and performs efficiently.
When you [upload documents](/ingestion), Docling processes the files, splits them into chunks, and stores them as separate, structured documents in your OpenSearch knowledge base.
You can use either Docling Serve or OpenRAG's built-in Docling ingestion pipeline to process documents.
<Tabs>
<TabItem value="serve" label="Docling Serve ingestion" default>
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.
</TabItem>
<TabItem value="docling" label="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).
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.
</TabItem>
</Tabs>
The OpenRAG frontend at `http://localhost:3000` now redirects to an OAuth callback login page for your OAuth provider.
A successful authentication opens OpenRAG with the required scopes for your connected storage.
To modify the Docling ingestion and embedding parameters, click <Icon name="Settings2" aria-hidden="true"/> **Settings** in the OpenRAG user interface.
To add knowledge from an OAuth-connected storage provider, do the following:
:::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**.
:::
1. Click **Add Knowledge**, and then select the storage provider, for example, **Google Drive**.
The **Add Cloud Knowledge** page opens.
2. To add files or folders from the connected storage, click **Add Files**.
Select the files or folders you want and click **Select**.
You can select multiple files.
3. When your files are selected, click **Ingest Files**.
The ingestion process can take some time depending on the size of your documents.
4. When ingestion is complete, your documents are available in the Knowledge screen.
* **Embedding model**: Select the model to use to generate vector embeddings for your documents.
If ingestion fails, click **Status** to view the logged error.
This is initially set during installation.
The recommended way to change this setting is in the OpenRAG **Settings** or your [OpenRAG configuration](/reference/configuration).
This will automatically update all relevant [OpenRAG flows](/agents) to use the new embedding model configuration.
## Monitor ingestion tasks
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.
If you want to use multiple embeddings models, similarity search (in the **Chat**) can take longer as it searching each model's embeddings separately.
When you upload files, process folders, or sync documents, OpenRAG processes them as background tasks.
A badge appears on the <Icon name="Bell" aria-hidden="true"/> **Tasks** icon when there are active tasks running.
To open the Tasks menu, click <Icon name="Bell" aria-hidden="true"/> **Tasks**.
* **Chunk size**: Set the number of characters for each text chunk when breaking down a file.
Larger chunks yield more context per chunk, but can include irrelevant information. Smaller chunks yield more precise semantic search, but can lack context.
The default value is 1000 characters, which is usually a good balance between context and precision.
**Active Tasks** shows tasks that are currently processing.
A **Pending** task is queued and waiting to start, a **Running** task is actively processing files, and a **Processing** task is performing ingestion operations. For each active task, you can find the task ID, start time, duration, the number of files processed so far, and the total files.
* **Chunk overlap**: Set the number of characters to overlap over chunk boundaries.
Use larger overlap values for documents where context is most important. Use smaller overlap values for simpler documents or when optimization is most important.
The default value is 200 characters, which represents an overlap of 20 percent if the **Chunk size** is 1000. This is suitable for general use. For faster processing, decrease the overlap to approximately 10 percent. For more complex documents where you need to preserve context across chunks, increase it to approximately 40 percent.
You can cancel active tasks by clicking <Icon name="X" aria-hidden="true"/> **Cancel**. Canceling a task stops processing immediately and marks the task as failed.
* **Table Structure**: Enables Docling's [`DocumentConverter`](https://docling-project.github.io/docling/reference/document_converter/) tool for parsing tables. Instead of treating tables as plain text, tables are output as structured table data with preserved relationships and metadata. This option is enabled by default.
## Explore knowledge
* **OCR**: Enables Optical Character Recognition (OCR) processing when extracting text from images and ingesting scanned documents. This setting is best suited for processing text-based documents faster with Docling's [`DocumentConverter`](https://docling-project.github.io/docling/reference/document_converter/). Images are ignored and not processed.
The **Knowledge** page lists the documents OpenRAG has ingested into the OpenSearch vector database's `documents` index.
This option is disabled by default. Enabling OCR can slow ingestion performance.
To explore your current knowledge, click <Icon name="Library" aria-hidden="true"/> **Knowledge**.
Click on a document to display the chunks derived from splitting the default documents into the vector database.
If OpenRAG detects that the local machine is running on macOS, OpenRAG uses the [ocrmac](https://www.piwheels.org/project/ocrmac/) OCR engine. Other platforms use [easyocr](https://www.jaided.ai/easyocr/).
Documents are processed with the default **Knowledge Ingest** flow, so if you want to split your documents differently, edit the **Knowledge Ingest** flow.
* **Picture descriptions**: Only applicable if **OCR** is enabled. Adds image descriptions generated by the [`SmolVLM-256M-Instruct`](https://huggingface.co/HuggingFaceTB/SmolVLM-Instruct) model. Enabling picture descriptions can slow ingestion performance.
<PartialModifyFlows />
### Set the local documents path {#set-the-local-documents-path}
## Create knowledge filters
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.
OpenRAG includes a knowledge filter system for organizing and managing document collections.
Knowledge filters are saved search configurations that allow you to create custom views of your document collection. They store search queries, filter criteria, and display settings that can be reused across different parts of OpenRAG.
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.
Knowledge filters help agents work more efficiently with large document collections by focusing their context within relevant documents sets.
## Delete knowledge {#delete-knowledge}
To create a knowledge filter, do the following:
To clear your entire knowledge base, delete the contents of the `./opensearch-data` folder in your OpenRAG installation directory.
This is a destructive operation that cannot be undone.
1. Click **Knowledge**, and then click <Icon name="Plus" aria-hidden="true"/> **Knowledge Filters**.
The **Knowledge Filter** pane appears.
2. Enter a **Name** and **Description**, and then click **Create Filter**.
A new filter is created with default settings that match all documents.
3. To modify the filter, click <Icon name="Library" aria-hidden="true"/> **Knowledge**, and then click your new filter to edit it in the **Knowledge Filter** pane.
## See also
The following filter options are configurable.
* **Search Query**: Enter text for semantic search, such as "financial reports from Q4".
* **Data Sources**: Select specific data sources or folders to include.
* **Document Types**: Filter by file type.
* **Owners**: Filter by who uploaded the documents.
* **Connectors**: Filter by connector types, such as local upload or Google Drive.
* **Response Limit**: Set maximum number of results. The default is `10`.
* **Score Threshold**: Set minimum relevance score. The default score is `0`.
4. When you're done editing the filter, click **Update Filter**.
5. To apply the filter to OpenRAG globally, click <Icon name="Library" aria-hidden="true"/> **Knowledge**, and then select the filter to apply. One filter can be enabled at a time.
To apply the filter to a single chat session, in the <Icon name="MessageSquare" aria-hidden="true"/> **Chat** window, click <Icon name="Funnel" aria-hidden="true"/>, and then select the filter to apply.
To delete the filter, in the **Knowledge Filter** pane, click **Delete Filter**.
## OpenRAG default configuration
OpenRAG automatically detects and configures the correct vector dimensions for embedding models, ensuring optimal search performance and compatibility.
The complete list of supported models is available at [`models_service.py` in the OpenRAG repository](https://github.com/langflow-ai/openrag/blob/main/src/services/models_service.py).
You can use custom embedding models by specifying them in your configuration.
If you use an unknown embedding model, OpenRAG automatically falls back to `1536` dimensions and logs a warning. The system continues to work, but search quality can be affected if the actual model dimensions differ from `1536`.
The default embedding dimension is `1536` and the default model is `text-embedding-3-small`.
For models with known vector dimensions, see [`settings.py` in the OpenRAG repository](https://github.com/langflow-ai/openrag/blob/main/src/config/settings.py).
* [Ingest knowledge](/ingestion)
* [Filter knowledge](/knowledge-filters)
* [Chat with knowledge](/chat)
* [Inspect and modify flows](/agents#inspect-and-modify-flows)

View file

@ -34,7 +34,7 @@ OpenRAG has two Docker Compose files. Both files deploy the same applications an
- Prepare model providers and credentials.
During [Application Onboarding](#application-onboarding), you must select language model and embedding model providers.
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.
@ -84,7 +84,7 @@ To install OpenRAG with Docker Compose, do the following:
LANGFLOW_SECRET_KEY=your_secret_key
```
`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).
`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` 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).
@ -159,7 +159,7 @@ To install OpenRAG with Docker Compose, do the following:
- **Backend API**: http://localhost:8000
- **Langflow**: http://localhost:7860
9. Continue with [Application Onboarding](#application-onboarding).
9. Continue with [application onboarding](#application-onboarding).
To stop `docling serve` when you're done with your OpenRAG deployment, run:

View file

@ -41,7 +41,7 @@ If you prefer running Podman or Docker containers and manually editing `.env` fi
- Prepare model providers and credentials.
During [Application Onboarding](#application-onboarding), you must select language model and embedding model providers.
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.
@ -180,24 +180,21 @@ If you encounter errors during installation, see [Troubleshoot OpenRAG](/support
## Set up OpenRAG with the TUI {#setup}
The TUI creates a `.env` file in your OpenRAG directory root and starts OpenRAG.
If the TUI detects a `.env` file in the OpenRAG root directory, it sources any variables from the `.env` file.
If the TUI detects OAuth credentials, it enforces the **Advanced Setup** path.
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.
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**.
<Tabs groupId="Setup method">
<TabItem value="Basic setup" label="Basic setup" default>
**Basic Setup** can generate all of the required values for OpenRAG. The OpenAI API key is optional and can be provided during onboarding.
**Basic Setup** does not set up OAuth connections for ingestion from cloud providers.
For OAuth setup, use **Advanced Setup**.
For information about the difference between basic (no auth) and OAuth in OpenRAG, see [Authentication and document access](/knowledge#auth).
1. To install OpenRAG with **Basic Setup**, click **Basic Setup** or press <kbd>1</kbd>.
1. To install OpenRAG with **Basic Setup**, click **Basic Setup** or press <kbd>1</kbd>.
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.
@ -211,20 +208,25 @@ If the TUI detects OAuth credentials, it enforces the **Advanced Setup** path.
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).
8. Continue with [application onboarding](#application-onboarding).
</TabItem>
<TabItem value="Advanced setup" label="Advanced setup">
1. To install OpenRAG with **Advanced Setup**, click **Advanced Setup** or press <kbd>2</kbd>.
1. To install OpenRAG with **Advanced Setup**, click **Advanced Setup** or press <kbd>2</kbd>.
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. Add your client and secret values for Google or Microsoft OAuth.
These values can be found with your OAuth provider.
For more information, see the [Google OAuth client](https://developers.google.com/identity/protocols/oauth2) or [Microsoft Graph OAuth client](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/graph-oauth) documentation.
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.
@ -239,21 +241,23 @@ If the TUI detects OAuth credentials, it enforces the **Advanced Setup** path.
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`.
You are presented with your provider's OAuth sign-in screen.
After sign-in, you are redirected to the redirect URI.
Two additional variables are available for Advanced Setup:
10. If you enabled OAuth connectors, you must sign in to your OAuth provider before being redirected to your OpenRAG instance.
The `LANGFLOW_PUBLIC_URL` controls where the Langflow web interface can be accessed. This is where users interact with their flows in a browser.
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.
The `WEBHOOK_BASE_URL` controls where the endpoint for `/connectors/CONNECTOR_TYPE/webhook` will be available.
This connection enables real-time document synchronization with external services.
* `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:
- Google Drive: `/connectors/google_drive/webhook`
- OneDrive: `/connectors/onedrive/webhook`
- SharePoint: `/connectors/sharepoint/webhook`
10. Continue with [Application Onboarding](#application-onboarding).
- 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).
</TabItem>
</Tabs>
@ -272,171 +276,180 @@ If you installed OpenRAG with `uvx`, run `uvx openrag`.
After installation, the TUI can deploy, manage, and upgrade your OpenRAG containers.
### Start all services
### Diagnostics
Click **Start All Services** to start the OpenRAG containers.
The TUI 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.
The TUI then pulls the images and deploys the containers with the following command.
```bash
docker compose up -d
```
The **Diagnostics** menu provides health monitoring for your container runtimes and monitoring of your OpenSearch security.
If images are missing, the TUI runs `docker compose pull`, then runs `docker compose up -d`.
### Status
### 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.
To view streaming logs, select the container you want to view, and press <kbd>l</kbd>.
To copy your logs, click **Copy to Clipboard**.
* **Logs**: To view streaming logs, select the container you want to view, and press <kbd>l</kbd>.
To copy the logs, click **Copy to Clipboard**.
To **upgrade** your containers, click **Upgrade**.
**Upgrade** runs `docker compose pull` and then `docker compose up -d --force-recreate`.
For more information, see [Upgrade OpenRAG containers with the TUI](#upgrade-openrag-containers-with-the-tui).
* **Upgrade**: Check for updates. For more information, see [upgrade OpenRAG](#upgrade).
To **reset** your containers, click **Reset**.
Reset gives you a completely fresh start.
Reset deletes all of your data, including OpenSearch data, uploaded documents, and authentication.
**Reset** runs two commands.
It first stops and removes all containers, volumes, and local images.
```
* **Reset**: This is a destructive action that [resets your containers](#reset-containers).
* **Native services**: 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.
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.
### Reset containers {#reset-containers}
:::warning
This is a destructive action that destroys and recreates all of your OpenRAG containers.
:::
To destroy and recreate your OpenRAG containers, go to the TUI [**Status** menu](#status), and then click **Reset**.
The **Reset** function runs two commands. First, it stops and removes all containers, volumes, and local images:
```bash
docker compose down --volumes --remove-orphans --rmi local
```
When the first command is complete, OpenRAG removes any additional Docker objects with `prune`.
Then, it removes any additional Docker objects with `docker system prune -f`.
```
docker system prune -f
```
If you reset your containers as part of reinstalling OpenRAG, continue the [reinstallation process](#reinstall) after resetting the containers.
### Native services status
### Start all services
A _native service_ in OpenRAG refers to a service run locally on your machine, and not within a container.
The `docling serve` process is a native service in OpenRAG, because it's a document processing service that is run on your local machine, and controlled separately from the containers.
On the TUI main page, click **Start All Services** to start the OpenRAG containers and launch OpenRAG itself.
To start or stop `docling serve` or any other native services, in the TUI Status menu, click **Stop** or **Restart**.
When you start all services, the following processes happen:
To view the status, port, or PID of a native service, in the TUI main menu, click [Status](#status).
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`.
## Upgrade OpenRAG {#upgrade}
To upgrade OpenRAG, upgrade the OpenRAG Python package, and then upgrade the OpenRAG containers using the OpenRAG TUI.
To upgrade OpenRAG, upgrade the OpenRAG Python package, and then upgrade the OpenRAG containers.
Upgrading the OpenRAG Python package updates the TUI and Python code, but container versions are controlled separately by environment variables in your `.env` file.
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.
### Upgrade OpenRAG python package
1. Stop your OpenRAG containers: In the OpenRAG TUI, go to the **Status** menu, and then click **Stop Services**.
Use the following steps to upgrade the OpenRAG Python package to the latest version from [PyPI](https://pypi.org/project/openrag/).
After upgrading the Python package, you should also [upgrade your OpenRAG containers](#upgrade-openrag-containers-with-the-tui).
2. Upgrade the OpenRAG Python package to the latest version from [PyPI](https://pypi.org/project/openrag/).
<Tabs groupId="Installation method">
<TabItem value="installer" label="Automatic installer / uvx" default>
<Tabs groupId="Installation method">
<TabItem value="installer" label="Automatic installer or uvx" default>
If you installed OpenRAG using the [automatic installer](#install) or [uvx](#install), follow these steps to upgrade:
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
```
```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
```
3. After upgrading the Python package, [upgrade your containers](#upgrade-openrag-containers-with-the-tui).
```bash
uvx --from openrag openrag
```
</TabItem>
<TabItem value="uv-add" label="Python project with uv add">
To upgrade to a specific version:
```bash
uvx --from openrag==0.1.33 openrag
```
</TabItem>
<TabItem value="uv-add" label="Python project (uv add)">
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
```
```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
```
```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
```
4. After upgrading the Python package, [upgrade your containers](#upgrade-openrag-containers-with-the-tui).
```bash
uv run openrag
```
</TabItem>
<TabItem value="uv-pip" label="Existing virtual environment with uv pip install">
</TabItem>
<TabItem value="uv-pip" label="Virtual environment (uv pip install)">
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
```
```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. After upgrading the Python package, [upgrade your containers](#upgrade-openrag-containers-with-the-tui).
```bash
uv run openrag
```
</TabItem>
</Tabs>
</TabItem>
</Tabs>
### Upgrade OpenRAG containers with the TUI {#upgrade-openrag-containers-with-the-tui}
3. Start the upgraded OpenRAG containers: In the OpenRAG TUI, click **Start All Services**, and then wait while the containers start.
After upgrading the OpenRAG Python package, upgrade your containers to ensure they match the `latest` version.
**Upgrade** runs `docker compose pull`, which pulls container images based on versions specified in your `.env` file.
`OPENRAG_VERSION` is set to `latest` by default, so it pulls the `latest` available container images.
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`.
1. In the OpenRAG TUI, click **Status**, and then click **Upgrade**.
2. When the upgrade completes, close the **Status** window and continue using OpenRAG.
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`.
If you encounter a `langflow container already exists` error during upgrade, see [Langflow container already exists during upgrade](/support/troubleshoot#langflow-container-already-exists-during-upgrade) in the troubleshooting guide.
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.
To pin container versions to a specific release other than `latest`, set the `OPENRAG_VERSION` in your `.env` file:
```bash
OPENRAG_VERSION=0.1.33
```
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).
For more information, see [System settings environment variables](/reference/configuration#system-settings).
## Diagnostics
The **Diagnostics** menu provides health monitoring for your container runtimes and monitoring of your OpenSearch security.
3. When the upgrade process is complete, you can close the **Status** window and continue using OpenRAG.
## Reinstall OpenRAG {#reinstall}
To reinstall OpenRAG with a completely fresh setup:
1. Reset your containers using the **Reset** button in the [TUI status](#status) menu.
This removes all containers, volumes, and data.
1. In the TUI **Status** menu, [reset your containers](#reset-containers) to destroy the existing OpenRAG containers and their data.
2. Optional: Delete your project's `.env` file.
The Reset operation does not remove your project's `.env` file, so your passwords, API keys, and OAuth settings can be preserved.
If you delete the `.env` file, run the [Set up OpenRAG with the TUI](#setup) process again to create a new configuration.
3. In the TUI Setup menu, follow these steps from [Basic Setup](#setup):
1. Click **Start All Services** to pull container images and start them.
2. Under **Native Services**, click **Start** to start the Docling service.
3. Click **Open App** to open the OpenRAG application.
4. Continue with [Application Onboarding](#application-onboarding).
The Reset operation doesn't remove your project's `.env` file, so your passwords, API keys, and OAuth settings can be preserved.
If you delete the `.env` file, you must run the [Set up OpenRAG with the TUI](#setup) process again to create a new configuration file.
3. Optional: Delete your OpenSearch knowledge base by deleting the contents of the `./opensearch-data` folder in your OpenRAG installation directory.
3. In the TUI **Setup** menu, repeat the [Basic Setup](#setup) process:
1. Click **Start All Services** to pull container images and start them.
2. Under **Native Services**, click **Start** to start the Docling service.
3. Click **Open App** to open the OpenRAG application.
4. Continue with [application onboarding](#application-onboarding).
If reinstalling OpenRAG and deleting the `.env` file doesn't reset setup or onboarding, see [Reinstalling OpenRAG doesn't reset onboarding](/support/troubleshoot#reinstalling-openrag-doesnt-reset-onboarding).

View file

@ -7,6 +7,7 @@ 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';
Use this quickstart to install OpenRAG, and then try some of OpenRAG's core features.
@ -84,7 +85,7 @@ You can complete this quickstart without going through the overview.
## Load and chat with documents {#chat-with-documents}
OpenRAG's knowledge base chat is powered by the [OpenRAG OpenSearch Agent](/agents).
Use the [OpenRAG **Chat**](/chat) to explore the documents in your OpenRAG database using natural language queries.
Some documents are included by default to get you started, and you can load your own documents.
1. In OpenRAG, click <Icon name="MessageSquare" aria-hidden="true"/> **Chat**.
@ -103,7 +104,7 @@ You can click a document to view the chunks of the document as they are stored i
**Folder** uploads an entire directory.
The default directory is the `/openrag-documents` subdirectory in your OpenRAG installation directory.
For information about the cloud storage provider options, see [Ingest files through OAuth connectors](/knowledge#oauth-ingestion).
For information about the cloud storage provider options, see [Ingest files with OAuth connectors](/ingestion#oauth-ingestion).
5. Return to the **Chat** window, and then ask a question related to the documents that you just uploaded.
@ -116,7 +117,7 @@ You can click a document to view the chunks of the document as they are stored i
* Click <Icon name="Settings2" aria-hidden="true"/> **Settings** to modify the knowledge ingestion settings.
For more information about knowledge bases and knowledge ingestion, see [OpenSearch in OpenRAG](/knowledge).
For more information, see [Configure knowledge](/knowledge) and [Ingest knowledge](/ingestion).
## Change the language model and chat settings {#change-components}
@ -128,14 +129,14 @@ You can click a document to view the chunks of the document as they are stored i
If Langflow requests login information, enter the `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` from the `.env` file in your OpenRAG installation directory.
The OpenRAG OpenSearch Agent flow opens in a new browser window.
The **OpenRAG OpenSearch Agent** flow opens in a new browser window.
![OpenRAG OpenSearch Agent flow](/img/opensearch-agent-flow.png)
3. For this quickstart, try changing the model.
Click the **Language Model** component, and then change the **Model Name** to a different OpenAI model.
When editing built-in flows, you can click **Restore flow** to revert the flow to its initial state.
After you edit a built-in flow, you can click **Restore flow** on the **Settings** page to revert the flow to its original state when you first installed OpenRAG.
4. Press <kbd>Command</kbd>+<kbd>S</kbd> (<kbd>Ctrl</kbd>+<kbd>S</kbd>) to save your changes.
@ -153,121 +154,12 @@ You can use these flows as-is or modify them to better suit your needs, as demon
You can send and receive requests with the Langflow API using Python, TypeScript, or curl.
1. Open the OpenRAG OpenSearch Agent flow in the Langflow visual editor: From the **Chat** window, click <Icon name="Settings2" aria-hidden="true"/> **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.
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 <Icon name="Plus" aria-hidden="true"/> **Add New**.
3. Name your key, and then click **Create API Key**.
4. Copy the API key and store it securely.
5. Exit the Langflow **Settings** page to return to the visual editor.
3. Click **Share**, and then select **API access** to get pregenerated code snippets that call the Langflow API and run the flow.
These code snippets construct API requests with your Langflow server URL (`LANGFLOW_SERVER_ADDRESS`), the flow to run (`FLOW_ID`), required headers (`LANGFLOW_API_KEY`, `Content-Type`), and a payload containing the required inputs to run the flow, including a default chat input message.
In production, you would modify the inputs to suit your application logic. For example, you could replace the default chat input message with dynamic user input.
<Tabs>
<TabItem value="python" label="Python">
```python
import requests
import os
import uuid
api_key = 'LANGFLOW_API_KEY'
url = "http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID" # The complete API endpoint URL for this flow
# Request payload configuration
payload = {
"output_type": "chat",
"input_type": "chat",
"input_value": "hello world!"
}
payload["session_id"] = str(uuid.uuid4())
headers = {"x-api-key": api_key}
try:
# Send API request
response = requests.request("POST", url, json=payload, headers=headers)
response.raise_for_status() # Raise exception for bad status codes
# Print response
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error making API request: {e}")
except ValueError as e:
print(f"Error parsing response: {e}")
```
</TabItem>
<TabItem value="typescript" label="TypeScript">
```typescript
const crypto = require('crypto');
const apiKey = 'LANGFLOW_API_KEY';
const payload = {
"output_type": "chat",
"input_type": "chat",
"input_value": "hello world!"
};
payload.session_id = crypto.randomUUID();
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
"x-api-key": apiKey
},
body: JSON.stringify(payload)
};
fetch('http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID', options)
.then(response => response.json())
.then(response => console.warn(response))
.catch(err => console.error(err));
```
</TabItem>
<TabItem value="curl" label="curl">
```bash
curl --request POST \
--url 'http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID?stream=false' \
--header 'Content-Type: application/json' \
--header "x-api-key: LANGFLOW_API_KEY" \
--data '{
"output_type": "chat",
"input_type": "chat",
"input_value": "hello world!"
}'
```
</TabItem>
</Tabs>
4. Copy your preferred snippet, and then run it:
* **Python**: Paste the snippet into a `.py` file, save it, and then run it with `python filename.py`.
* **TypeScript**: Paste the snippet into a `.ts` file, save it, and then run it with `ts-node filename.ts`.
* **curl**: Paste and run snippet directly in your terminal.
If the request is successful, the response includes many details about the flow run, including the session ID, inputs, outputs, components, durations, and more.
In production, you won't pass the raw response to the user in its entirety.
Instead, you extract and reformat relevant fields for different use cases, as demonstrated in the [Langflow quickstart](https://docs.langflow.org/quickstart#extract-data-from-the-response).
For example, you could pass the chat output text to a front-end user-facing application, and store specific fields in logs and backend data stores for monitoring, chat history, or analytics.
You could also pass the output from one flow as input to another flow.
<PartialIntegrateChat />
## 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 with your preferred configuration because some settings are immutable after initial setup.
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).
* **Learn more about OpenRAG**: Explore OpenRAG and the OpenRAG documentation to learn more about its features and functionality.

View file

@ -10,13 +10,18 @@ OpenRAG connects and amplifies three popular, proven open-source projects into o
* [Langflow](https://docs.langflow.org): Langflow is a versatile tool for building and deploying AI agents and MCP servers. It supports all major LLMs, vector databases, and a growing library of AI tools.
OpenRAG uses several built-in flows, and it provides full access to all Langflow features through the embedded Langflow visual editor.
By customizing the built-in flows or creating your own flows, every part of the OpenRAG stack interchangeable. You can modify any aspect of the flows from basic settings, like changing the language model, to replacing entire components. You can also write your own custom Langflow components, integrate MCP servers, call APIs, and leverage any other functionality provided by Langflow.
* [OpenSearch](https://docs.opensearch.org/latest/): OpenSearch is a community-driven, Apache 2.0-licensed open source search and analytics suite that makes it easy to ingest, search, visualize, and analyze data.
It provides powerful hybrid search capabilities with enterprise-grade security and multi-tenancy support.
* [Docling](https://docling-project.github.io/docling/): Docling simplifies document processing, parsing diverse formats — including advanced PDF understanding — and providing seamless integrations with the gen AI ecosystem.
OpenRAG uses OpenSearch as the underlying vector database for storing and retrieving your documents and associated vector data (embeddings). You can ingest documents from a variety of sources, including your local filesystem and OAuth authenticated connectors to popular cloud storage services.
OpenRAG builds on Langflow's familiar interface while adding OpenSearch for vector storage and Docling for simplified document parsing. It uses opinionated flows that serve as ready-to-use recipes for ingestion, retrieval, and generation from familiar sources like Google Drive, OneDrive, and SharePoint.
* [Docling](https://docling-project.github.io/docling/): Docling simplifies document processing, supports many file formats and advanced PDF parsing, and provides seamless integrations with the generative AI ecosystem.
What's more, every part of the stack is interchangeable: You can write your own custom components in Python, try different language models, and customize your flows to build a personalized agentic RAG system.
OpenRAG uses Docling to parse and chunk documents that are stored in your OpenSearch knowledge base.
:::tip
Ready to get started? Try the [quickstart](/quickstart) to install OpenRAG and start exploring in minutes.
@ -52,12 +57,12 @@ flowchart TD
ext --> backend
```
* The **OpenRAG Backend** is the central orchestration service that coordinates all other components.
* **OpenRAG backend**: The central orchestration service that coordinates all other components.
* **Langflow** provides a visual workflow engine for building AI agents, and connects to **OpenSearch** for vector storage and retrieval.
* **Langflow**: This container runs a Langflow instance. It provides the embedded Langflow visual editor for editing and creating flow, and it connects to the **OpenSearch** container for vector storage and retrieval.
* **Docling Serve** is a local document processing service managed by the **OpenRAG Backend**.
* **Docling Serve**: This is a local document processing service managed by the **OpenRAG backend**.
* **External connectors** integrate third-party cloud storage services through OAuth authenticated connections to the **OpenRAG Backend**, allowing synchronization of external storage with your OpenSearch knowledge base.
* **External connectors**: Integrate third-party cloud storage services with OAuth authenticated connectors to the **OpenRAG backend**, allowing you to load documents from external storage to your OpenSearch knowledge base.
* The **OpenRAG Frontend** provides the user interface for interacting with the platform.
* **OpenRAG frontend**: Provides the user interface for interacting with the OpenRAG platform.

View file

@ -23,32 +23,47 @@ The Docker Compose files are populated with values from your `.env`, so you don'
Environment variables always take precedence over other variables.
### Set environment variables
### Set environment variables {#set-environment-variables}
To set environment variables, do the following.
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.
To set mutable environment variables, do the following:
1. Stop OpenRAG with the TUI or Docker Compose.
1. Stop OpenRAG.
2. Set the values in the `.env` file:
```bash
LOG_LEVEL=DEBUG
LOG_FORMAT=json
SERVICE_NAME=openrag-dev
```
3. Start OpenRAG.
Updating provider API keys or provider endpoints in the `.env` file will not take effect after [Application onboarding](/install#application-onboarding). To change these values, you must:
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.
1. Stop OpenRAG.
2. Remove the containers:
```
```bash
docker-compose down
```
3. Update the values in your `.env` file.
4. Start OpenRAG containers.
```
4. Start OpenRAG with Docker Compose:
```bash
docker-compose up -d
```
5. Complete [Application onboarding](/install#application-onboarding) again.
5. Repeat [application onboarding](/install#application-onboarding). The values in your `.env` file are automatically populated.
## Supported environment variables
@ -56,30 +71,30 @@ All OpenRAG configuration can be controlled through environment variables.
### AI provider settings
Configure which AI models and providers OpenRAG uses for language processing and embeddings.
For more information, see [Application onboarding](/install#application-onboarding).
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).
| Variable | Default | Description |
|----------|---------|-------------|
| `EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model for vector search. |
| `LLM_MODEL` | `gpt-4o-mini` | Language model for the chat agent. |
| `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. |
| `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` | - | Your OpenAI API key. Optional. Can be provided during application onboarding when installing OpenRAG. |
| `PROVIDER_API_KEY` | - | API key for the model provider. |
| `PROVIDER_ENDPOINT` | - | Custom provider endpoint. Only used for IBM or Ollama providers. |
| `PROVIDER_PROJECT_ID` | - | Project ID for providers. Only required for the IBM watsonx.ai provider. |
| `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. |
### Document processing
Control how OpenRAG processes and ingests documents into your knowledge base.
For more information, see [Ingestion](/ingestion).
Control how OpenRAG [processes and ingests documents](/ingestion) into your knowledge base.
| Variable | Default | Description |
|----------|---------|-------------|
| `CHUNK_OVERLAP` | `200` | Overlap between chunks. |
| `CHUNK_SIZE` | `1000` | Text chunk size for document processing. |
| `DISABLE_INGEST_WITH_LANGFLOW` | `false` | Disable Langflow ingestion pipeline. |
| `DOCLING_OCR_ENGINE` | - | OCR engine for document processing. |
| `DOCLING_OCR_ENGINE` | Set by OS | OCR engine for document processing. For macOS, `ocrmac`. For any other OS, `easyocr`. |
| `OCR_ENABLED` | `false` | Enable OCR for image processing. |
| `OPENRAG_DOCUMENTS_PATHS` | `./openrag-documents` | Document paths for ingestion. |
| `PICTURE_DESCRIPTIONS_ENABLED` | `false` | Enable picture descriptions. |
@ -91,18 +106,18 @@ Configure Langflow authentication.
| Variable | Default | Description |
|----------|---------|-------------|
| `LANGFLOW_AUTO_LOGIN` | `False` | Enable auto-login for Langflow. |
| `LANGFLOW_CHAT_FLOW_ID` | pre-filled | This value is pre-filled. The default value is found in [.env.example](https://github.com/langflow-ai/openrag/blob/main/.env.example). |
| `LANGFLOW_ENABLE_SUPERUSER_CLI` | `False` | Enable superuser CLI. |
| `LANGFLOW_INGEST_FLOW_ID` | pre-filled | This value is pre-filled. The default value is found in [.env.example](https://github.com/langflow-ai/openrag/blob/main/.env.example). |
| `LANGFLOW_KEY` | auto-generated | Explicit Langflow API key. |
| `LANGFLOW_NEW_USER_IS_ACTIVE` | `False` | New users are active by default. |
| `LANGFLOW_PUBLIC_URL` | `http://localhost:7860` | Public URL for Langflow. |
| `LANGFLOW_SECRET_KEY` | - | Secret key for Langflow internal operations. |
| `LANGFLOW_SUPERUSER` | - | Langflow admin username. Required. |
| `LANGFLOW_SUPERUSER_PASSWORD` | - | Langflow admin password. Required. |
| `LANGFLOW_URL` | `http://localhost:7860` | Langflow URL. |
| `NUDGES_FLOW_ID` | pre-filled | This value is pre-filled. The default value is found in [.env.example](https://github.com/langflow-ai/openrag/blob/main/.env.example). |
| `SYSTEM_PROMPT` | "You are a helpful AI assistant with access to a knowledge base. Answer questions based on the provided context." | System prompt for the Langflow agent. |
| `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_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. |
| `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
@ -134,31 +149,29 @@ 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` | `latest` | Langflow Docker image version. |
| `LOG_FORMAT` | - | Log format (set to "json" for JSON output). |
| `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). |
| `MAX_WORKERS` | - | Maximum number of workers for document processing. |
| `OPENRAG_VERSION` | `latest` | OpenRAG Docker image version. |
| `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) |
| `SERVICE_NAME` | `openrag` | Service name for logging. |
| `SESSION_SECRET` | auto-generated | Session management. |
| `SESSION_SECRET` | Automatically generated | Session management. |
## Langflow runtime overrides
Langflow runtime overrides allow you to modify component settings at runtime without changing the base configuration.
You can modify [flow](/agents) settings at runtime without permanently changing the flow's configuration.
Runtime overrides are implemented through **tweaks** - parameter modifications that are passed to specific Langflow components during flow execution.
Runtime overrides are implemented through _tweaks_, which are one-time parameter modifications that are passed to specific Langflow components during flow execution.
For more information on tweaks, see [Input schema (tweaks)](https://docs.langflow.org/concepts-publish#input-schema).
For more information on tweaks, see the Langflow documentation on [Input schema (tweaks)](https://docs.langflow.org/concepts-publish#input-schema).
## Default values and fallbacks
When no environment variables or configuration file values are provided, OpenRAG uses default values.
These values can be found in the code base at the following locations.
If a variable isn't set by environment variables or a configuration file, OpenRAG can use a default value if one is defined in the codebase.
Default values can be found in the OpenRAG repository:
### OpenRAG configuration defaults
* OpenRAG configuration: [`config_manager.py`](https://github.com/langflow-ai/openrag/blob/main/src/config/config_manager.py)
These values are defined in [`config_manager.py` in the OpenRAG repository](https://github.com/langflow-ai/openrag/blob/main/src/config/config_manager.py).
* System configuration: [`settings.py`](https://github.com/langflow-ai/openrag/blob/main/src/config/settings.py)
### System configuration defaults
These fallback values are defined in [`settings.py` in the OpenRAG repository](https://github.com/langflow-ai/openrag/blob/main/src/config/settings.py).
* Logging configuration: [`logging_config.py`](https://github.com/langflow-ai/openrag/blob/main/src/utils/logging_config.py)

View file

@ -77,7 +77,7 @@ On macOS, this cache directory is typically a user cache directory such as `/Use
uvx openrag
```
If you do not need OCR, you can disable OCR-based processing in your ingestion settings to avoid requiring `easyocr`.
If you don't need OCR, you can disable OCR-based processing in your ingestion settings to avoid requiring `easyocr`.
## Upgrade fails due to Langflow container already exists {#langflow-container-already-exists-during-upgrade}
@ -124,8 +124,8 @@ If reinstalling the Langflow container doesn't resolve the issue, you must reset
Then, you can retry the upgrade.
:::warning
This is a destructive operation that completely resets your OpenRAG containers and removes all OpenRAG data, including OpenSearch data, uploaded documents, and authentication details.
Your `.env` file is preserved, so your configuration settings remain intact, but all other data is lost.
This is a destructive operation that destroys your OpenRAG containers and their contents.
However, your `.env` file (configuration settings) and `./opensearch-data` (OpenSearch knowledge base) are preserved.
:::
To reset your installation, stop your containers, and then completely remove them.
@ -210,4 +210,17 @@ After removing the containers, retry the upgrade in the OpenRAG TUI by clicking
```
</TabItem>
</Tabs>
</Tabs>
## Reinstalling OpenRAG doesn't reset onboarding {#reinstalling-openrag-doesnt-reset-onboarding}
If you [reinstall OpenRAG](/install#reinstall), you can restore your installation to it's original, default state by resetting the containers _and_ deleting the `.env` file.
When you start OpenRAG after doing this, you should be prompted to go through the initial setup and onboarding process again.
Due to a known issue, the onboarding process might not reset when you reinstall OpenRAG.
If this occurs, [install OpenRAG in a new Python project directory](/install#install) (with `uv init` and `uv add openrag`).
## Document ingestion or similarity search issues
See [Troubleshoot ingestion](/ingestion#troubleshoot-ingestion).

View file

@ -24,9 +24,25 @@ const sidebars = {
"get-started/quickstart",
"get-started/install",
"get-started/docker",
"core-components/agents",
"core-components/knowledge",
"core-components/ingestion",
{
type: "doc",
id: "core-components/agents",
label: "Flows",
},
{
type: "category",
label: "Knowledge",
items: [
"core-components/knowledge",
"core-components/ingestion",
"core-components/knowledge-filters",
],
},
{
type: "doc",
id: "core-components/chat",
label: "Chat",
},
"reference/configuration",
"support/troubleshoot",
],

View file

@ -5712,6 +5712,7 @@
"endpoint_name": null,
"id": "5488df7c-b93f-4f87-a446-b67028bc0813",
"is_component": false,
"locked": true,
"last_tested_version": "1.7.0.dev19",
"name": "OpenSearch Ingestion Flow",
"tags": [

View file

@ -42,11 +42,18 @@ export const useGetOpenAIModelsQuery = (
async function getOpenAIModels(): Promise<ModelsResponse> {
const url = new URL("/api/models/openai", window.location.origin);
const body: { api_key?: string } = {};
if (params?.apiKey) {
url.searchParams.set("api_key", params.apiKey);
body.api_key = params.apiKey;
}
const response = await fetch(url.toString());
const response = await fetch(url.toString(), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (response.ok) {
return await response.json();
} else {
@ -77,11 +84,18 @@ export const useGetAnthropicModelsQuery = (
async function getAnthropicModels(): Promise<ModelsResponse> {
const url = new URL("/api/models/anthropic", window.location.origin);
const body: { api_key?: string } = {};
if (params?.apiKey) {
url.searchParams.set("api_key", params.apiKey);
body.api_key = params.apiKey;
}
const response = await fetch(url.toString());
const response = await fetch(url.toString(), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (response.ok) {
return await response.json();
} else {
@ -147,17 +161,28 @@ export const useGetIBMModelsQuery = (
async function getIBMModels(): Promise<ModelsResponse> {
const url = new URL("/api/models/ibm", window.location.origin);
const body: {
endpoint?: string;
api_key?: string;
project_id?: string;
} = {};
if (params?.endpoint) {
url.searchParams.set("endpoint", params.endpoint);
body.endpoint = params.endpoint;
}
if (params?.apiKey) {
url.searchParams.set("api_key", params.apiKey);
body.api_key = params.apiKey;
}
if (params?.projectId) {
url.searchParams.set("project_id", params.projectId);
body.project_id = params.projectId;
}
const response = await fetch(url.toString());
const response = await fetch(url.toString(), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (response.ok) {
return await response.json();
} else {

View file

@ -652,10 +652,9 @@ function KnowledgeSourcesPage() {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
})
.then(() => {
// Only reset form values if the API call was successful
// Flow restoration is complete - backend already updated flow with current provider/model
// Just reset the UI form value for system prompt
setSystemPrompt(DEFAULT_AGENT_SETTINGS.system_prompt);
// Trigger model update to default model
handleModelChange(DEFAULT_AGENT_SETTINGS.llm_model);
closeDialog(); // Close after successful completion
})
.catch((error) => {

View file

@ -8,9 +8,14 @@ logger = get_logger(__name__)
async def get_openai_models(request, models_service, session_manager):
"""Get available OpenAI models"""
try:
# Get API key from query parameters
query_params = dict(request.query_params)
api_key = query_params.get("api_key")
# Get API key from request body
api_key = None
try:
body = await request.json()
api_key = body.get("api_key") if body else None
except Exception:
# Body might be empty or invalid JSON, continue to fallback
pass
# If no API key provided, try to get it from stored configuration
if not api_key:
@ -26,7 +31,7 @@ async def get_openai_models(request, models_service, session_manager):
if not api_key:
return JSONResponse(
{
"error": "OpenAI API key is required either as query parameter or in configuration"
"error": "OpenAI API key is required either in request body or in configuration"
},
status_code=400,
)
@ -42,9 +47,14 @@ async def get_openai_models(request, models_service, session_manager):
async def get_anthropic_models(request, models_service, session_manager):
"""Get available Anthropic models"""
try:
# Get API key from query parameters
query_params = dict(request.query_params)
api_key = query_params.get("api_key")
# Get API key from request body
api_key = None
try:
body = await request.json()
api_key = body.get("api_key") if body else None
except Exception:
# Body might be empty or invalid JSON, continue to fallback
pass
# If no API key provided, try to get it from stored configuration
if not api_key:
@ -60,7 +70,7 @@ async def get_anthropic_models(request, models_service, session_manager):
if not api_key:
return JSONResponse(
{
"error": "Anthropic API key is required either as query parameter or in configuration"
"error": "Anthropic API key is required either in request body or in configuration"
},
status_code=400,
)
@ -112,11 +122,19 @@ async def get_ollama_models(request, models_service, session_manager):
async def get_ibm_models(request, models_service, session_manager):
"""Get available IBM Watson models"""
try:
# Get parameters from query parameters if provided
query_params = dict(request.query_params)
endpoint = query_params.get("endpoint")
api_key = query_params.get("api_key")
project_id = query_params.get("project_id")
# Get parameters from request body if provided
endpoint = None
api_key = None
project_id = None
try:
body = await request.json()
if body:
endpoint = body.get("endpoint")
api_key = body.get("api_key")
project_id = body.get("project_id")
except Exception:
# Body might be empty or invalid JSON, continue to fallback
pass
config = get_openrag_config()
# If no API key provided, try to get it from stored configuration
@ -132,7 +150,7 @@ async def get_ibm_models(request, models_service, session_manager):
if not api_key:
return JSONResponse(
{
"error": "WatsonX API key is required either as query parameter or in configuration"
"error": "WatsonX API key is required either in request body or in configuration"
},
status_code=400,
)
@ -149,7 +167,7 @@ async def get_ibm_models(request, models_service, session_manager):
if not endpoint:
return JSONResponse(
{
"error": "Endpoint is required either as query parameter or in configuration"
"error": "Endpoint is required either in request body or in configuration"
},
status_code=400,
)
@ -166,7 +184,7 @@ async def get_ibm_models(request, models_service, session_manager):
if not project_id:
return JSONResponse(
{
"error": "Project ID is required either as query parameter or in configuration"
"error": "Project ID is required either in request body or in configuration"
},
status_code=400,
)

View file

@ -1105,7 +1105,7 @@ async def create_app():
session_manager=services["session_manager"],
)
),
methods=["GET"],
methods=["POST"],
),
Route(
"/models/anthropic",
@ -1116,7 +1116,7 @@ async def create_app():
session_manager=services["session_manager"],
)
),
methods=["GET"],
methods=["POST"],
),
Route(
"/models/ollama",
@ -1138,7 +1138,7 @@ async def create_app():
session_manager=services["session_manager"],
)
),
methods=["GET", "POST"],
methods=["POST"],
),
# Onboarding endpoint
Route(

View file

@ -424,15 +424,69 @@ class FlowsService:
]
logger.info(f"Updating {flow_type} flow model values")
# Use LLM provider for most flows, embedding provider for ingest flows
provider_to_use = embedding_provider if flow_type in ["ingest", "url_ingest"] else llm_provider
update_result = await self.change_langflow_model_value(
provider=provider_to_use,
embedding_model=config.knowledge.embedding_model if flow_type in ["ingest", "url_ingest"] else None,
llm_model=config.agent.llm_model if flow_type not in ["ingest", "url_ingest"] else None,
endpoint=endpoint,
flow_configs=single_flow_config,
)
# For retrieval flow: need to update both LLM and embedding (potentially different providers)
# For ingest flows: only update embedding
# For other flows: only update LLM
if flow_type == "retrieval":
# Retrieval flow uses both LLM and embedding models
# Update LLM first
llm_endpoint = getattr(llm_provider_config, "endpoint", None)
llm_result = await self.change_langflow_model_value(
provider=llm_provider,
embedding_model=None,
llm_model=config.agent.llm_model,
endpoint=llm_endpoint,
flow_configs=single_flow_config,
)
if not llm_result.get("success"):
logger.warning(
f"Failed to update LLM in {flow_type} flow: {llm_result.get('error', 'Unknown error')}"
)
# Update embedding model
embedding_provider_config = config.get_embedding_provider_config()
embedding_endpoint = getattr(embedding_provider_config, "endpoint", None)
embedding_result = await self.change_langflow_model_value(
provider=embedding_provider,
embedding_model=config.knowledge.embedding_model,
llm_model=None,
endpoint=embedding_endpoint,
flow_configs=single_flow_config,
)
if not embedding_result.get("success"):
logger.warning(
f"Failed to update embedding in {flow_type} flow: {embedding_result.get('error', 'Unknown error')}"
)
# Consider it successful if either update succeeded
update_result = {
"success": llm_result.get("success") or embedding_result.get("success"),
"llm_result": llm_result,
"embedding_result": embedding_result,
}
elif flow_type in ["ingest", "url_ingest"]:
# Ingest flows only need embedding model
embedding_provider_config = config.get_embedding_provider_config()
embedding_endpoint = getattr(embedding_provider_config, "endpoint", None)
update_result = await self.change_langflow_model_value(
provider=embedding_provider,
embedding_model=config.knowledge.embedding_model,
llm_model=None,
endpoint=embedding_endpoint,
flow_configs=single_flow_config,
)
else:
# Other flows (nudges) only need LLM model
llm_endpoint = getattr(llm_provider_config, "endpoint", None)
update_result = await self.change_langflow_model_value(
provider=llm_provider,
embedding_model=None,
llm_model=config.agent.llm_model,
endpoint=llm_endpoint,
flow_configs=single_flow_config,
)
if update_result.get("success"):
logger.info(

View file

@ -1,8 +1,5 @@
"""OpenRAG Terminal User Interface package."""
from importlib.metadata import version
from .utils.version_check import get_current_version
try:
__version__ = version("openrag")
except Exception:
__version__ = "unknown"
__version__ = get_current_version()

View file

@ -479,6 +479,100 @@ class ContainerManager:
image=image,
)
async def get_container_version(self) -> Optional[str]:
"""
Get the version tag from existing containers.
Checks the backend container image tag to determine version.
Returns:
Version string if found, None if no containers exist or version can't be determined
"""
try:
# Check for backend container first (most reliable)
success, stdout, _ = await self._run_runtime_command(
["ps", "--all", "--filter", "name=openrag-backend", "--format", "{{.Image}}"]
)
if success and stdout.strip():
image_tag = stdout.strip().splitlines()[0].strip()
if not image_tag or image_tag == "N/A":
return None
# Extract version from image tag (e.g., langflowai/openrag-backend:0.1.47)
if ":" in image_tag:
version = image_tag.split(":")[-1]
# If version is "latest", check .env file for OPENRAG_VERSION
if version == "latest":
# Try to get version from .env file
try:
from pathlib import Path
env_file = Path(".env")
if env_file.exists():
env_content = env_file.read_text()
for line in env_content.splitlines():
line = line.strip()
if line.startswith("OPENRAG_VERSION"):
env_version = line.split("=", 1)[1].strip()
# Remove quotes if present
env_version = env_version.strip("'\"")
if env_version and env_version != "latest":
return env_version
except Exception:
pass
# If still "latest", we can't determine version - return None
return None
# Return version if it looks like a version number (not "latest")
if version and version != "latest":
return version
# Fallback: check all containers for version tags
success, stdout, _ = await self._run_runtime_command(
["ps", "--all", "--format", "{{.Image}}"]
)
if success and stdout.strip():
images = stdout.strip().splitlines()
for image in images:
image = image.strip()
if "openrag" in image.lower() and ":" in image:
version = image.split(":")[-1]
if version and version != "latest":
return version
except Exception as e:
logger.debug(f"Error getting container version: {e}")
return None
async def check_version_mismatch(self) -> tuple[bool, Optional[str], str]:
"""
Check if existing containers have a different version than the current TUI.
Returns:
Tuple of (has_mismatch, container_version, tui_version)
"""
try:
from ..utils.version_check import get_current_version
tui_version = get_current_version()
if tui_version == "unknown":
return False, None, tui_version
container_version = await self.get_container_version()
if container_version is None:
# No containers exist, no mismatch
return False, None, tui_version
# Compare versions
from ..utils.version_check import compare_versions
comparison = compare_versions(container_version, tui_version)
has_mismatch = comparison != 0
return has_mismatch, container_version, tui_version
except Exception as e:
logger.debug(f"Error checking version mismatch: {e}")
return False, None, "unknown"
async def get_service_status(
self, force_refresh: bool = False
) -> Dict[str, ServiceInfo]:
@ -764,6 +858,14 @@ class ContainerManager:
yield False, "No container runtime available"
return
# Ensure OPENRAG_VERSION is set in .env file
try:
from ..managers.env_manager import EnvManager
env_manager = EnvManager()
env_manager.ensure_openrag_version()
except Exception:
pass # Continue even if version setting fails
# Determine GPU mode
if cpu_mode is None:
use_gpu = self.use_gpu_compose

View file

@ -68,6 +68,9 @@ class EnvConfig:
# OpenSearch data path
opensearch_data_path: str = "./opensearch-data"
# Container version (linked to TUI version)
openrag_version: str = ""
# Validation errors
validation_errors: Dict[str, str] = field(default_factory=dict)
@ -149,6 +152,7 @@ class EnvManager:
"LANGFLOW_NEW_USER_IS_ACTIVE": "langflow_new_user_is_active",
"LANGFLOW_ENABLE_SUPERUSER_CLI": "langflow_enable_superuser_cli",
"DISABLE_INGEST_WITH_LANGFLOW": "disable_ingest_with_langflow",
"OPENRAG_VERSION": "openrag_version",
}
loaded_from_file = False
@ -193,6 +197,17 @@ class EnvManager:
if not self.config.langflow_secret_key:
self.config.langflow_secret_key = self.generate_langflow_secret_key()
# Set OPENRAG_VERSION to TUI version if not already set
if not self.config.openrag_version:
try:
from ..utils.version_check import get_current_version
current_version = get_current_version()
if current_version != "unknown":
self.config.openrag_version = current_version
except Exception:
# If we can't get version, leave it empty (will use 'latest' from compose)
pass
# Configure autologin based on whether password is set
if not self.config.langflow_superuser_password:
@ -344,6 +359,18 @@ class EnvManager:
f.write(
f"OPENSEARCH_DATA_PATH={self._quote_env_value(self.config.opensearch_data_path)}\n"
)
# Set OPENRAG_VERSION to TUI version
if self.config.openrag_version:
f.write(f"OPENRAG_VERSION={self._quote_env_value(self.config.openrag_version)}\n")
else:
# Fallback: try to get current version
try:
from ..utils.version_check import get_current_version
current_version = get_current_version()
if current_version != "unknown":
f.write(f"OPENRAG_VERSION={self._quote_env_value(current_version)}\n")
except Exception:
pass
f.write("\n")
# Provider API keys and endpoints (optional - can be set during onboarding)
@ -514,6 +541,73 @@ class EnvManager:
return base_fields + oauth_fields + flow_fields + optional_fields
def ensure_openrag_version(self) -> None:
"""Ensure OPENRAG_VERSION is set in .env file to match TUI version."""
try:
from ..utils.version_check import get_current_version
current_version = get_current_version()
if current_version == "unknown":
return
# Check if OPENRAG_VERSION is already set in .env
if self.env_file.exists():
env_content = self.env_file.read_text()
if "OPENRAG_VERSION" in env_content:
# Already set, check if it needs updating
for line in env_content.splitlines():
if line.strip().startswith("OPENRAG_VERSION"):
existing_value = line.split("=", 1)[1].strip()
existing_value = sanitize_env_value(existing_value)
if existing_value == current_version:
# Already correct, no update needed
return
break
# Set or update OPENRAG_VERSION
self.config.openrag_version = current_version
# Update .env file
if self.env_file.exists():
# Read existing content
lines = self.env_file.read_text().splitlines()
updated = False
new_lines = []
for line in lines:
if line.strip().startswith("OPENRAG_VERSION"):
# Replace existing line
new_lines.append(f"OPENRAG_VERSION={self._quote_env_value(current_version)}")
updated = True
else:
new_lines.append(line)
# If not found, add it after OPENSEARCH_DATA_PATH or at the end
if not updated:
insert_pos = len(new_lines)
for i, line in enumerate(new_lines):
if "OPENSEARCH_DATA_PATH" in line:
insert_pos = i + 1
break
new_lines.insert(insert_pos, f"OPENRAG_VERSION={self._quote_env_value(current_version)}")
with open(self.env_file, 'w') as f:
f.write("\n".join(new_lines) + "\n")
f.flush()
os.fsync(f.fileno())
else:
# Create new .env file with just OPENRAG_VERSION
with open(self.env_file, 'w') as f:
content = (
f"# OpenRAG Environment Configuration\n"
f"# Generated by OpenRAG TUI\n\n"
f"OPENRAG_VERSION={self._quote_env_value(current_version)}\n"
)
f.write(content)
f.flush()
os.fsync(f.fileno())
except Exception as e:
logger.debug(f"Error ensuring OPENRAG_VERSION: {e}")
def generate_compose_volume_mounts(self) -> List[str]:
"""Generate Docker Compose volume mount strings from documents paths."""
is_valid, _, validated_paths = validate_documents_paths(

View file

@ -20,6 +20,8 @@ from ..managers.docling_manager import DoclingManager
from ..utils.platform import RuntimeType
from ..widgets.command_modal import CommandOutputModal
from ..widgets.flow_backup_warning_modal import FlowBackupWarningModal
from ..widgets.version_mismatch_warning_modal import VersionMismatchWarningModal
from ..widgets.upgrade_instructions_modal import UpgradeInstructionsModal
from ..widgets.diagnostics_notification import notify_with_diagnostics
@ -63,7 +65,7 @@ class MonitorScreen(Screen):
def on_unmount(self) -> None:
"""Clean up when the screen is unmounted."""
if hasattr(self, 'docling_manager'):
if hasattr(self, "docling_manager"):
self.docling_manager.cleanup()
super().on_unmount()
self._follow_service = None
@ -218,7 +220,7 @@ class MonitorScreen(Screen):
docling_status_value = docling_status["status"]
docling_running = docling_status_value == "running"
docling_starting = docling_status_value == "starting"
if docling_running:
docling_status_text = "running"
docling_style = "bold green"
@ -228,9 +230,15 @@ class MonitorScreen(Screen):
else:
docling_status_text = "stopped"
docling_style = "bold red"
docling_port = f"{docling_status['host']}:{docling_status['port']}" if (docling_running or docling_starting) else "N/A"
docling_pid = str(docling_status.get("pid")) if docling_status.get("pid") else "N/A"
docling_port = (
f"{docling_status['host']}:{docling_status['port']}"
if (docling_running or docling_starting)
else "N/A"
)
docling_pid = (
str(docling_status.get("pid")) if docling_status.get("pid") else "N/A"
)
if self.docling_table:
self.docling_table.add_row(
@ -238,7 +246,7 @@ class MonitorScreen(Screen):
Text(docling_status_text, style=docling_style),
docling_port,
docling_pid,
"Start/Stop/Logs"
"Start/Stop/Logs",
)
# Restore docling selection when it was the last active table
if self._last_selected_table == "docling":
@ -321,27 +329,55 @@ class MonitorScreen(Screen):
self.operation_in_progress = True
try:
# Check for port conflicts before attempting to start
ports_available, conflicts = await self.container_manager.check_ports_available()
(
ports_available,
conflicts,
) = await self.container_manager.check_ports_available()
if not ports_available:
# Show error notification instead of modal
conflict_msgs = []
for service_name, port, error_msg in conflicts[:3]: # Show first 3
conflict_msgs.append(f"{service_name} (port {port})")
conflict_str = ", ".join(conflict_msgs)
if len(conflicts) > 3:
conflict_str += f" and {len(conflicts) - 3} more"
self.notify(
f"Cannot start services: Port conflicts detected for {conflict_str}. "
f"Please stop the conflicting services first.",
severity="error",
timeout=10
timeout=10,
)
# Refresh to show current state
await self._refresh_services()
return
# Check for version mismatch
(
has_mismatch,
container_version,
tui_version,
) = await self.container_manager.check_version_mismatch()
if has_mismatch and container_version:
# Show warning modal and wait for user decision
should_continue = await self.app.push_screen_wait(
VersionMismatchWarningModal(container_version, tui_version)
)
if not should_continue:
self.notify("Start cancelled", severity="information")
return
# Ensure OPENRAG_VERSION is set in .env BEFORE starting services
# This ensures docker compose reads the correct version
try:
from ..managers.env_manager import EnvManager
env_manager = EnvManager()
env_manager.ensure_openrag_version()
# Small delay to ensure .env file is written and flushed
await asyncio.sleep(0.5)
except Exception:
pass # Continue even if version setting fails
# Show command output in modal dialog
command_generator = self.container_manager.start_services(cpu_mode)
modal = CommandOutputModal(
@ -391,27 +427,30 @@ class MonitorScreen(Screen):
self.operation_in_progress = False
async def _upgrade_services(self) -> None:
"""Upgrade services with progress updates."""
"""Check TUI version and show upgrade instructions."""
self.operation_in_progress = True
try:
# Check for flow backups before upgrading
if self._check_flow_backups():
# Show warning modal and wait for user decision
should_continue = await self.app.push_screen_wait(
FlowBackupWarningModal(operation="upgrade")
from ..utils.version_check import check_if_latest
# Check if current version is latest
is_latest, latest_version, current_version = await check_if_latest()
if is_latest:
# Show "this is the latest version" toast
self.notify(
f"You are running the latest version ({current_version}).",
severity="success",
timeout=5,
)
if not should_continue:
self.notify("Upgrade cancelled", severity="information")
return
# Show command output in modal dialog
command_generator = self.container_manager.upgrade_services()
modal = CommandOutputModal(
"Upgrading Services",
command_generator,
on_complete=None, # We'll refresh in on_screen_resume instead
else:
# Show upgrade instructions in a modal dialog
await self.app.push_screen_wait(
UpgradeInstructionsModal(current_version, latest_version)
)
except Exception as e:
self.notify(
f"Error checking version: {str(e)}", severity="error", timeout=10
)
self.app.push_screen(modal)
finally:
self.operation_in_progress = False
@ -428,7 +467,7 @@ class MonitorScreen(Screen):
if not should_continue:
self.notify("Reset cancelled", severity="information")
return
# Show command output in modal dialog
command_generator = self.container_manager.reset_services()
modal = CommandOutputModal(
@ -443,10 +482,11 @@ class MonitorScreen(Screen):
def _check_flow_backups(self) -> bool:
"""Check if there are any flow backups in ./flows/backup directory."""
from pathlib import Path
backup_dir = Path("flows/backup")
if not backup_dir.exists():
return False
try:
# Check if there are any .json files in the backup directory
backup_files = list(backup_dir.glob("*.json"))
@ -465,7 +505,7 @@ class MonitorScreen(Screen):
f"Cannot start docling serve: {error_msg}. "
f"Please stop the conflicting service first.",
severity="error",
timeout=10
timeout=10,
)
# Refresh to show current state
await self._refresh_services()
@ -483,7 +523,9 @@ class MonitorScreen(Screen):
if success:
self.notify(message, severity="information")
else:
self.notify(f"Failed to start docling serve: {message}", severity="error")
self.notify(
f"Failed to start docling serve: {message}", severity="error"
)
# Refresh again to show final status (running or stopped)
await self._refresh_services()
except Exception as e:
@ -501,7 +543,9 @@ class MonitorScreen(Screen):
if success:
self.notify(message, severity="information")
else:
self.notify(f"Failed to stop docling serve: {message}", severity="error")
self.notify(
f"Failed to stop docling serve: {message}", severity="error"
)
# Refresh the services table to show updated status
await self._refresh_services()
except Exception as e:
@ -517,7 +561,9 @@ class MonitorScreen(Screen):
if success:
self.notify(message, severity="information")
else:
self.notify(f"Failed to restart docling serve: {message}", severity="error")
self.notify(
f"Failed to restart docling serve: {message}", severity="error"
)
# Refresh the services table to show updated status
await self._refresh_services()
except Exception as e:
@ -528,6 +574,7 @@ class MonitorScreen(Screen):
def _view_docling_logs(self) -> None:
"""View docling serve logs."""
from .logs import LogsScreen
self.app.push_screen(LogsScreen(initial_service="docling-serve"))
def _strip_ansi_codes(self, text: str) -> str:
@ -728,7 +775,7 @@ class MonitorScreen(Screen):
Button("Upgrade", variant="warning", id=f"upgrade-btn{suffix}")
)
controls.mount(Button("Reset", variant="error", id=f"reset-btn{suffix}"))
except Exception as e:
notify_with_diagnostics(
self.app, f"Error updating controls: {e}", severity="error"
@ -748,6 +795,7 @@ class MonitorScreen(Screen):
# Use a random suffix for unique IDs
import random
suffix = f"-{random.randint(10000, 99999)}"
# Add docling serve controls
@ -755,17 +803,21 @@ class MonitorScreen(Screen):
docling_status_value = docling_status["status"]
docling_running = docling_status_value == "running"
docling_starting = docling_status_value == "starting"
if docling_running:
docling_controls.mount(
Button("Stop", variant="error", id=f"docling-stop-btn{suffix}")
)
docling_controls.mount(
Button("Restart", variant="primary", id=f"docling-restart-btn{suffix}")
Button(
"Restart", variant="primary", id=f"docling-restart-btn{suffix}"
)
)
elif docling_starting:
# Show disabled button or no button when starting
start_btn = Button("Starting...", variant="warning", id=f"docling-start-btn{suffix}")
start_btn = Button(
"Starting...", variant="warning", id=f"docling-start-btn{suffix}"
)
start_btn.disabled = True
docling_controls.mount(start_btn)
else:
@ -805,6 +857,7 @@ class MonitorScreen(Screen):
if selected_service:
# Push the logs screen with the selected service
from .logs import LogsScreen
logs_screen = LogsScreen(initial_service=selected_service)
self.app.push_screen(logs_screen)
else:
@ -927,7 +980,9 @@ class MonitorScreen(Screen):
except Exception:
pass
def _focus_services_table(self, row: str | None = None, set_last: bool = True) -> None:
def _focus_services_table(
self, row: str | None = None, set_last: bool = True
) -> None:
"""Focus the services table and update selection."""
if not self.services_table:
return

View file

@ -15,6 +15,7 @@ from ..managers.container_manager import ContainerManager, ServiceStatus
from ..managers.env_manager import EnvManager
from ..managers.docling_manager import DoclingManager
from ..widgets.command_modal import CommandOutputModal
from ..widgets.version_mismatch_warning_modal import VersionMismatchWarningModal
class WelcomeScreen(Screen):
@ -450,6 +451,28 @@ class WelcomeScreen(Screen):
# Step 1: Start container services first (to create the network)
if self.container_manager.is_available():
# Check for version mismatch before starting
has_mismatch, container_version, tui_version = await self.container_manager.check_version_mismatch()
if has_mismatch and container_version:
# Show warning modal and wait for user decision
should_continue = await self.app.push_screen_wait(
VersionMismatchWarningModal(container_version, tui_version)
)
if not should_continue:
self.notify("Start cancelled", severity="information")
return
# Ensure OPENRAG_VERSION is set in .env BEFORE starting services
# This ensures docker compose reads the correct version
try:
from ..managers.env_manager import EnvManager
env_manager = EnvManager()
env_manager.ensure_openrag_version()
# Small delay to ensure .env file is written and flushed
import asyncio
await asyncio.sleep(0.5)
except Exception:
pass # Continue even if version setting fails
command_generator = self.container_manager.start_services()
modal = CommandOutputModal(
"Starting Container Services",

View file

@ -0,0 +1,175 @@
"""Version checking utilities for OpenRAG TUI."""
from typing import Optional, Tuple
from utils.logging_config import get_logger
logger = get_logger(__name__)
async def get_latest_docker_version(image_name: str = "langflowai/openrag-backend") -> Optional[str]:
"""
Get the latest version tag from Docker Hub for OpenRAG containers.
Args:
image_name: Name of the Docker image to check (default: "langflowai/openrag-backend")
Returns:
Latest version string if found, None otherwise
"""
try:
import httpx
async with httpx.AsyncClient(timeout=10.0) as client:
# Docker Hub API v2 endpoint for tags
url = f"https://hub.docker.com/v2/repositories/{image_name}/tags/"
params = {"page_size": 100, "ordering": "-last_updated"}
response = await client.get(url, params=params)
if response.status_code == 200:
data = response.json()
tags = data.get("results", [])
# Filter out non-version tags and find the latest version
version_tags = []
for tag in tags:
tag_name = tag.get("name", "")
# Skip architecture-specific tags (amd64, arm64) and "latest"
if tag_name in ["latest", "amd64", "arm64"]:
continue
# Skip tags that don't look like version numbers
# Version format: X.Y.Z (e.g., 0.1.47)
# Check if it starts with a digit and contains only digits, dots, and hyphens
if tag_name and tag_name[0].isdigit():
# Remove dots and hyphens, check if rest is digits
cleaned = tag_name.replace(".", "").replace("-", "")
if cleaned.isdigit():
version_tags.append(tag_name)
if not version_tags:
return None
# Sort versions properly and return the latest
# Use a tuple-based sort key for proper version comparison
def version_sort_key(v: str) -> tuple:
"""Convert version string to tuple for sorting."""
try:
parts = []
for part in v.split('.'):
# Extract numeric part
numeric_part = ''
for char in part:
if char.isdigit():
numeric_part += char
else:
break
parts.append(int(numeric_part) if numeric_part else 0)
# Pad to at least 3 parts for consistent comparison
while len(parts) < 3:
parts.append(0)
return tuple(parts)
except Exception:
# Fallback: return tuple of zeros if parsing fails
return (0, 0, 0)
version_tags.sort(key=version_sort_key)
return version_tags[-1]
else:
logger.warning(f"Docker Hub API returned status {response.status_code}")
return None
except Exception as e:
logger.debug(f"Error checking Docker Hub for latest version: {e}")
return None
def get_current_version() -> str:
"""
Get the current installed version of OpenRAG.
Returns:
Version string or "unknown" if not available
"""
try:
from importlib.metadata import version
return version("openrag")
except Exception:
try:
from tui import __version__
return __version__
except Exception:
return "unknown"
def compare_versions(version1: str, version2: str) -> int:
"""
Compare two version strings.
Args:
version1: First version string
version2: Second version string
Returns:
-1 if version1 < version2, 0 if equal, 1 if version1 > version2
"""
try:
# Simple version comparison by splitting on dots and comparing parts
def normalize_version(v: str) -> list:
parts = []
for part in v.split('.'):
# Split on non-numeric characters and take the first numeric part
numeric_part = ''
for char in part:
if char.isdigit():
numeric_part += char
else:
break
parts.append(int(numeric_part) if numeric_part else 0)
return parts
v1_parts = normalize_version(version1)
v2_parts = normalize_version(version2)
# Pad shorter version with zeros
max_len = max(len(v1_parts), len(v2_parts))
v1_parts.extend([0] * (max_len - len(v1_parts)))
v2_parts.extend([0] * (max_len - len(v2_parts)))
for i in range(max_len):
if v1_parts[i] < v2_parts[i]:
return -1
elif v1_parts[i] > v2_parts[i]:
return 1
return 0
except Exception as e:
logger.debug(f"Error comparing versions: {e}")
# Fallback: string comparison
if version1 < version2:
return -1
elif version1 > version2:
return 1
else:
return 0
async def check_if_latest() -> Tuple[bool, Optional[str], str]:
"""
Check if the current version is the latest available on Docker Hub.
Returns:
Tuple of (is_latest, latest_version, current_version)
"""
current = get_current_version()
latest = await get_latest_docker_version()
if latest is None:
# If we can't check, assume current is latest
return True, None, current
if current == "unknown":
# If we can't determine current version, assume it's not latest
return False, latest, current
comparison = compare_versions(current, latest)
is_latest = comparison >= 0
return is_latest, latest, current

View file

@ -0,0 +1,112 @@
"""Upgrade instructions modal for OpenRAG TUI."""
from textual.app import ComposeResult
from textual.containers import Container, Horizontal
from textual.screen import ModalScreen
from textual.widgets import Button, Static, Label
class UpgradeInstructionsModal(ModalScreen[bool]):
"""Modal dialog showing upgrade instructions when not on latest version."""
DEFAULT_CSS = """
UpgradeInstructionsModal {
align: center middle;
}
#dialog {
width: 75;
height: auto;
border: solid #3f3f46;
background: #27272a;
padding: 0;
}
#title {
background: #3f3f46;
color: #fafafa;
padding: 1 2;
text-align: center;
width: 100%;
text-style: bold;
}
#message {
padding: 2;
color: #fafafa;
}
#button-row {
width: 100%;
height: auto;
align: center middle;
padding: 1;
margin-top: 1;
}
#button-row Button {
margin: 0 1;
min-width: 16;
background: #27272a;
color: #fafafa;
border: round #52525b;
text-style: none;
tint: transparent 0%;
}
#button-row Button:hover {
background: #27272a !important;
color: #fafafa !important;
border: round #52525b;
tint: transparent 0%;
text-style: none;
}
#button-row Button:focus {
background: #27272a !important;
color: #fafafa !important;
border: round #ec4899;
tint: transparent 0%;
text-style: none;
}
"""
def __init__(self, current_version: str, latest_version: str):
"""Initialize the upgrade instructions modal.
Args:
current_version: Current TUI version
latest_version: Latest available version
"""
super().__init__()
self.current_version = current_version
self.latest_version = latest_version
def compose(self) -> ComposeResult:
"""Create the modal dialog layout."""
with Container(id="dialog"):
yield Label("📦 Upgrade Available", id="title")
yield Static(
f"Current version: {self.current_version}\n"
f"Latest version: {self.latest_version}\n\n"
"To upgrade the TUI:\n"
"1. Exit TUI (press 'q')\n"
"2. Run one of:\n"
" • pip install --upgrade openrag\n"
" • uv pip install --upgrade openrag\n"
" • uvx --from openrag openrag\n"
"3. Restart: openrag\n\n"
"After upgrading, containers will automatically use the new version.",
id="message"
)
with Horizontal(id="button-row"):
yield Button("Close", id="close-btn")
def on_mount(self) -> None:
"""Focus the close button."""
self.query_one("#close-btn", Button).focus()
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle button presses."""
self.dismiss(True) # Just close the modal

View file

@ -0,0 +1,114 @@
"""Version mismatch warning modal for OpenRAG TUI."""
from textual.app import ComposeResult
from textual.containers import Container, Horizontal
from textual.screen import ModalScreen
from textual.widgets import Button, Static, Label
class VersionMismatchWarningModal(ModalScreen[bool]):
"""Modal dialog to warn about version mismatch before starting services."""
DEFAULT_CSS = """
VersionMismatchWarningModal {
align: center middle;
}
#dialog {
width: 70;
height: auto;
border: solid #3f3f46;
background: #27272a;
padding: 0;
}
#title {
background: #3f3f46;
color: #fafafa;
padding: 1 2;
text-align: center;
width: 100%;
text-style: bold;
}
#message {
padding: 2;
color: #fafafa;
text-align: center;
}
#button-row {
width: 100%;
height: auto;
align: center middle;
padding: 1;
margin-top: 1;
}
#button-row Button {
margin: 0 1;
min-width: 16;
background: #27272a;
color: #fafafa;
border: round #52525b;
text-style: none;
tint: transparent 0%;
}
#button-row Button:hover {
background: #27272a !important;
color: #fafafa !important;
border: round #52525b;
tint: transparent 0%;
text-style: none;
}
#button-row Button:focus {
background: #27272a !important;
color: #fafafa !important;
border: round #ec4899;
tint: transparent 0%;
text-style: none;
}
"""
def __init__(self, container_version: str, tui_version: str):
"""Initialize the warning modal.
Args:
container_version: Version of existing containers
tui_version: Current TUI version
"""
super().__init__()
self.container_version = container_version
self.tui_version = tui_version
def compose(self) -> ComposeResult:
"""Create the modal dialog layout."""
with Container(id="dialog"):
yield Label("⚠ Version Mismatch Detected", id="title")
yield Static(
f"Existing containers are running version {self.container_version}\n"
f"Current TUI version is {self.tui_version}\n\n"
f"Starting services will update containers to version {self.tui_version}.\n"
f"This may cause compatibility issues with your flows.\n\n"
f"⚠️ Please backup your flows before continuing:\n"
f" Your flows are in ./flows/ directory\n\n"
f"Do you want to continue?",
id="message"
)
with Horizontal(id="button-row"):
yield Button("Cancel", id="cancel-btn")
yield Button("Continue", id="continue-btn")
def on_mount(self) -> None:
"""Focus the cancel button by default for safety."""
self.query_one("#cancel-btn", Button).focus()
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle button presses."""
if event.button.id == "continue-btn":
self.dismiss(True) # User wants to continue
else:
self.dismiss(False) # User cancelled