Merge branch 'main' into 2409dependabot/github_actions/actions/setup-python-6

This commit is contained in:
Edwin Jose 2026-01-16 09:19:28 -05:00 committed by GitHub
commit dbfa432de6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 2116 additions and 91 deletions

View file

@ -66,6 +66,10 @@ EMBEDDING_MODEL=
# OPTIONAL url for openrag link to langflow in the UI # OPTIONAL url for openrag link to langflow in the UI
LANGFLOW_PUBLIC_URL= LANGFLOW_PUBLIC_URL=
# OPTIONAL: Override the full docling-serve URL (e.g., for remote instances)
# If not set, auto-detects host and uses port 5001
# DOCLING_SERVE_URL=http://my-docling-server:5001
# OPTIONAL: Override host for docling service (for special networking setups) # OPTIONAL: Override host for docling service (for special networking setups)
# HOST_DOCKER_INTERNAL=host.containers.internal # HOST_DOCKER_INTERNAL=host.containers.internal

View file

@ -69,8 +69,7 @@ jobs:
tag: langflowai/openrag-backend tag: langflowai/openrag-backend
platform: linux/arm64 platform: linux/arm64
arch: arm64 arch: arm64
#runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-2] runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: RagRunner
# frontend # frontend
- image: frontend - image: frontend
@ -84,8 +83,7 @@ jobs:
tag: langflowai/openrag-frontend tag: langflowai/openrag-frontend
platform: linux/arm64 platform: linux/arm64
arch: arm64 arch: arm64
#runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-2] runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: RagRunner
# langflow # langflow
- image: langflow - image: langflow
@ -99,8 +97,7 @@ jobs:
tag: langflowai/openrag-langflow tag: langflowai/openrag-langflow
platform: linux/arm64 platform: linux/arm64
arch: arm64 arch: arm64
#runs-on: self-hosted runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: RagRunner
# opensearch # opensearch
- image: opensearch - image: opensearch
@ -114,9 +111,7 @@ jobs:
tag: langflowai/openrag-opensearch tag: langflowai/openrag-opensearch
platform: linux/arm64 platform: linux/arm64
arch: arm64 arch: arm64
#runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-2] runs-on: [self-hosted, Linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
#runs-on: self-hosted
runs-on: RagRunner
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}

View file

@ -23,7 +23,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 20.20.0
cache: npm cache: npm
cache-dependency-path: ./docs/package-lock.json cache-dependency-path: ./docs/package-lock.json

View file

@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 20.20.0
cache: npm cache: npm
cache-dependency-path: ./docs/package-lock.json cache-dependency-path: ./docs/package-lock.json

View file

@ -1,4 +1,4 @@
FROM node:18-slim FROM node:20.20.0-slim
# Set working directory # Set working directory
WORKDIR /app WORKDIR /app

View file

@ -15,68 +15,20 @@ OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables
<a href="https://deepwiki.com/langflow-ai/openrag"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a> <a href="https://deepwiki.com/langflow-ai/openrag"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
</div> ## Install OpenRAG
<div align="center">
<a href="#quickstart" style="color: #0366d6;">Quickstart</a> &nbsp;&nbsp;|&nbsp;&nbsp;
<a href="#install-python-package" style="color: #0366d6;">Python package</a> &nbsp;&nbsp;|&nbsp;&nbsp;
<a href="#docker-or-podman-installation" style="color: #0366d6;">Docker or Podman</a> &nbsp;&nbsp;|&nbsp;&nbsp;
<a href="#development" style="color: #0366d6;">Development</a> &nbsp;&nbsp;|&nbsp;&nbsp;
<a href="#troubleshooting" style="color: #0366d6;">Troubleshooting</a>
</div>
## Quickstart To get started with OpenRAG, see the installation guides in the OpenRAG documentation:
To run OpenRAG without creating or modifying any project files, use `uvx`: * [Quickstart](https://docs.openr.ag/quickstart)
* [Install the OpenRAG Python package](https://docs.openr.ag/install-options)
```bash * [Deploy self-managed services with Docker or Podman](https://docs.openr.ag/docker)
uvx openrag
```
This command runs OpenRAG without installing it to your project or globally.
To run a specific version of OpenRAG, run `uvx --from openrag==VERSION openrag`.
## Install Python package
To add the OpenRAG Python package to a Python project, use `uv`:
1. Create a new project with a virtual environment using `uv init`:
```bash
uv init YOUR_PROJECT_NAME
cd YOUR_PROJECT_NAME
```
The `(venv)` prompt doesn't change, but `uv` commands will automatically use the project's virtual environment.
For more information on virtual environments, see the [uv documentation](https://docs.astral.sh/uv/pip/environments).
2. Add OpenRAG to your project:
```bash
uv add openrag
```
To add a specific version of OpenRAG, run `uv add openrag==VERSION`.
3. Start the OpenRAG terminal user interface (TUI):
```bash
uv run openrag
```
4. Continue with the [Quickstart](https://docs.openr.ag/quickstart).
For all installation options, see the [OpenRAG installation guide](https://docs.openr.ag/install).
## Docker or Podman installation
By default, OpenRAG automatically starts the required containers and helps you manage them.
To install OpenRAG with self-managed containers, see the [OpenRAG installation guide](https://docs.openr.ag/docker).
## Development ## Development
For developers wanting to contribute to OpenRAG or set up a development environment, see [CONTRIBUTING.md](CONTRIBUTING.md). For developers who want to [contribute to OpenRAG](https://docs.openr.ag/support/contribute) or set up a development environment, see [CONTRIBUTING.md](CONTRIBUTING.md).
## Troubleshooting ## Troubleshooting
For common issues and fixes, see [Troubleshoot OpenRAG](https://docs.openr.ag/support/troubleshoot). For assistance with OpenRAG, see [Troubleshoot OpenRAG](https://docs.openr.ag/support/troubleshoot) and visit the [Discussions page](https://github.com/langflow-ai/openrag/discussions).
To report a bug or submit a feature request, visit the [Issues page](https://github.com/langflow-ai/openrag/issues).

View file

@ -3,5 +3,10 @@ services:
environment: environment:
- NVIDIA_DRIVER_CAPABILITIES=compute,utility - NVIDIA_DRIVER_CAPABILITIES=compute,utility
- NVIDIA_VISIBLE_DEVICES=all - NVIDIA_VISIBLE_DEVICES=all
gpus: all deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]

View file

@ -29,7 +29,7 @@ services:
- "9200:9200" - "9200:9200"
- "9600:9600" - "9600:9600"
volumes: volumes:
- ${OPENSEARCH_DATA_PATH:-./opensearch-data}:/usr/share/opensearch/data:Z - ${OPENSEARCH_DATA_PATH:-./opensearch-data}:/usr/share/opensearch/data:U,z
dashboards: dashboards:
image: opensearchproject/opensearch-dashboards:3.0.0 image: opensearchproject/opensearch-dashboards:3.0.0
@ -81,7 +81,7 @@ services:
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
volumes: volumes:
- ${OPENRAG_DOCUMENTS_PATH:-./openrag-documents}:/app/openrag-documents:Z - ${OPENRAG_DOCUMENTS_PATH:-./openrag-documents}:/app/openrag-documents:Z
- ${OPENRAG_KEYS_PATH:-./keys}:/app/keys:Z - ${OPENRAG_KEYS_PATH:-./keys}:/app/keys:U,z
- ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z - ${OPENRAG_FLOWS_PATH:-./flows}:/app/flows:U,z
- ${OPENRAG_CONFIG_PATH:-./config}:/app/config:Z - ${OPENRAG_CONFIG_PATH:-./config}:/app/config:Z
- ${OPENRAG_DATA_PATH:-./data}:/app/data:Z - ${OPENRAG_DATA_PATH:-./data}:/app/data:Z

View file

@ -0,0 +1,5 @@
GPU acceleration isn't required for most use cases.
OpenRAG's CPU-only deployment doesn't prevent you from using GPU acceleration in external services, such as Ollama servers.
GPU acceleration is required only for specific use cases, typically involving customization of the ingestion flows or ingestion logic.
For example, writing alternate ingest logic in OpenRAG that uses GPUs directly in the container, or customizing the ingestion flows to use Langflow's Docling component with GPU acceleration instead of OpenRAG's `docling serve` service.

View file

@ -15,4 +15,6 @@ If a provider offers only one type, you must select two providers.
<PartialOllamaModels /> <PartialOllamaModels />
::: :::
* Optional: Install GPU support with an NVIDIA GPU, [CUDA](https://docs.nvidia.com/cuda/) support, and compatible NVIDIA drivers on the OpenRAG host machine. If you don't have GPU capabilities, OpenRAG provides an alternate CPU-only deployment. * Optional: Install GPU support with an NVIDIA GPU, [CUDA](https://docs.nvidia.com/cuda/) support, and compatible NVIDIA drivers on the OpenRAG host machine.
If you don't have GPU capabilities, OpenRAG provides an alternate CPU-only deployment that is suitable for most use cases.
The default CPU-only deployment doesn't prevent you from using GPU acceleration in external services, such as Ollama servers.

View file

@ -12,6 +12,7 @@ import PartialPrereqWindows from '@site/docs/_partial-prereq-windows.mdx';
import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx'; import PartialPrereqPython from '@site/docs/_partial-prereq-python.mdx';
import PartialInstallNextSteps from '@site/docs/_partial-install-next-steps.mdx'; import PartialInstallNextSteps from '@site/docs/_partial-install-next-steps.mdx';
import PartialOllamaModels from '@site/docs/_partial-ollama-models.mdx'; import PartialOllamaModels from '@site/docs/_partial-ollama-models.mdx';
import PartialGpuModeTip from '@site/docs/_partial-gpu-mode-tip.mdx';
To manage your own OpenRAG services, deploy OpenRAG with Docker or Podman. To manage your own OpenRAG services, deploy OpenRAG with Docker or Podman.
@ -116,7 +117,17 @@ The following variables are required or recommended:
3. Deploy the OpenRAG containers locally using the appropriate Docker Compose configuration for your environment: 3. Deploy the OpenRAG containers locally using the appropriate Docker Compose configuration for your environment:
* **GPU-accelerated deployment**: If your host machine has an NVIDIA GPU with CUDA support and compatible NVIDIA drivers, use the base `docker-compose.yml` file with the `docker-compose.gpu.yml` override. * **CPU-only deployment** (default, recommended): If your host machine doesn't have NVIDIA GPU support, use the base `docker-compose.yml` file:
```bash title="Docker"
docker compose up -d
```
```bash title="Podman"
podman compose up -d
```
* **GPU-accelerated deployment**: If your host machine has an NVIDIA GPU with CUDA support and compatible NVIDIA drivers, use the base `docker-compose.yml` file with the `docker-compose.gpu.yml` override:
```bash title="Docker" ```bash title="Docker"
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
@ -126,15 +137,9 @@ The following variables are required or recommended:
podman compose -f docker-compose.yml -f docker-compose.gpu.yml up -d podman compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
``` ```
* **CPU-only deployment** (default): If your host machine doesn't have NVIDIA GPU support, use the base `docker-compose.yml` file. :::tip
<PartialGpuModeTip />
```bash title="Docker" :::
docker compose up -d
```
```bash title="Podman"
podman compose up -d
```
4. Wait for the OpenRAG containers to start, and then confirm that all containers are running: 4. Wait for the OpenRAG containers to start, and then confirm that all containers are running:

View file

@ -3,6 +3,8 @@ title: Use the TUI
slug: /tui slug: /tui
--- ---
import PartialGpuModeTip from '@site/docs/_partial-gpu-mode-tip.mdx';
The OpenRAG Terminal User Interface (TUI) provides a simplified and guided experience for configuring, managing, and monitoring your OpenRAG deployment directly from the terminal. The OpenRAG Terminal User Interface (TUI) provides a simplified and guided experience for configuring, managing, and monitoring your OpenRAG deployment directly from the terminal.
![OpenRAG TUI Interface](@site/static/img/openrag_tui_dec_2025.png) ![OpenRAG TUI Interface](@site/static/img/openrag_tui_dec_2025.png)
@ -36,6 +38,10 @@ In the TUI, click **Status**, and then click **Switch to GPU Mode** or **Switch
This change requires restarting all OpenRAG services because each mode has its own `docker-compose` file. This change requires restarting all OpenRAG services because each mode has its own `docker-compose` file.
:::tip
<PartialGpuModeTip />
:::
## Exit the OpenRAG TUI ## Exit the OpenRAG TUI
To exit the OpenRAG TUI, press <kbd>q</kbd> on the TUI main page. To exit the OpenRAG TUI, press <kbd>q</kbd> on the TUI main page.

View file

@ -0,0 +1,12 @@
---
title: OpenRAG APIs and SDKs
slug: /reference/api-sdk-overview
---
You can use OpenRAG's APIs and SDKs to integrate and extend OpenRAG's capabilities:
* [Python SDK](https://github.com/langflow-ai/openrag/tree/main/sdks/python)
* [TypeScript/JavaScript SDK](https://github.com/langflow-ai/openrag/tree/main/sdks/typescript)
<!-- TBD: MCP: See https://github.com/langflow-ai/openrag/pull/729 -->
<!-- TBD: API Reference: See https://github.com/langflow-ai/openrag/issues/734 -->

View file

@ -8,12 +8,113 @@ import {themes as prismThemes} from 'prism-react-renderer';
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
const isProduction = process.env.NODE_ENV === 'production';
/** @type {import('@docusaurus/types').Config} */ /** @type {import('@docusaurus/types').Config} */
const config = { const config = {
title: 'OpenRAG', title: 'OpenRAG',
tagline: 'Open Source RAG Platform', tagline: 'Open Source RAG Platform',
favicon: 'img/favicon.ico', favicon: 'img/favicon.ico',
headTags: [
...(isProduction
? [
// Google Consent Mode - Set defaults before Google tags load
{
tagName: "script",
attributes: {},
innerHTML: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Set default consent to denied
gtag('consent', 'default', {
'ad_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'analytics_storage': 'denied'
});
`,
},
// TrustArc Consent Update Listener
{
tagName: "script",
attributes: {},
innerHTML: `
(function() {
function updateGoogleConsent() {
if (typeof window.truste !== 'undefined' && window.truste.cma) {
var consent = window.truste.cma.callApi('getConsent', window.location.href) || {};
// Map TrustArc categories to Google consent types
// Category 0 = Required, 1 = Functional, 2 = Advertising, 3 = Analytics
var hasAdvertising = consent[2] === 1;
var hasAnalytics = consent[3] === 1;
gtag('consent', 'update', {
'ad_storage': hasAdvertising ? 'granted' : 'denied',
'ad_user_data': hasAdvertising ? 'granted' : 'denied',
'ad_personalization': hasAdvertising ? 'granted' : 'denied',
'analytics_storage': hasAnalytics ? 'granted' : 'denied'
});
}
}
// Listen for consent changes
if (window.addEventListener) {
window.addEventListener('cm_data_subject_consent_changed', updateGoogleConsent);
window.addEventListener('cm_consent_preferences_set', updateGoogleConsent);
}
// Initial check after TrustArc loads
if (document.readyState === 'complete') {
updateGoogleConsent();
} else {
window.addEventListener('load', updateGoogleConsent);
}
})();
`,
},
// IBM Analytics Configuration (required for TrustArc)
{
tagName: "script",
attributes: {},
innerHTML: `
window._ibmAnalytics = {
"settings": {
"name": "DataStax",
"tealiumProfileName": "ibm-subsidiary",
},
"trustarc": {
"privacyPolicyLink": "https://ibm.com/privacy"
}
};
window.digitalData = {
"page": {
"pageInfo": {
"ibm": {
"siteId": "IBM_DataStax",
}
},
"category": {
"primaryCategory": "PC230"
}
}
};
`,
},
// IBM Common Stats Script - loads TrustArc
{
tagName: "script",
attributes: {
src: "//1.www.s81c.com/common/stats/ibm-common.js",
async: "true",
},
},
]
: []),
],
// Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future // Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future
future: { future: {
v4: true, // Improve compatibility with the upcoming Docusaurus v4 v4: true, // Improve compatibility with the upcoming Docusaurus v4
@ -26,7 +127,7 @@ const config = {
baseUrl: process.env.BASE_URL ? process.env.BASE_URL : '/', baseUrl: process.env.BASE_URL ? process.env.BASE_URL : '/',
// Control search engine indexing - set to true to prevent indexing // Control search engine indexing - set to true to prevent indexing
noIndex: true, noIndex: false,
// GitHub pages deployment config. // GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these. // If you aren't using GitHub pages, you don't need these.
@ -75,6 +176,19 @@ const config = {
theme: { theme: {
customCss: './src/css/custom.css', customCss: './src/css/custom.css',
}, },
// Use preset-classic sitemap https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-sitemap
sitemap: {
lastmod: 'date',
changefreq: 'weekly',
priority: 0.5,
ignorePatterns: ['/tags/**'],
filename: 'sitemap.xml',
createSitemapItems: async (params) => {
const {defaultCreateSitemapItems, ...rest} = params;
const items = await defaultCreateSitemapItems(rest);
return items.filter((item) => !item.url.includes('/page/'));
},
},
}), }),
], ],
], ],
@ -115,12 +229,22 @@ const config = {
{ {
html: `<div class="footer-links"> html: `<div class="footer-links">
<span>© ${new Date().getFullYear()} OpenRAG</span> <span>© ${new Date().getFullYear()} OpenRAG</span>
<span id="preferenceCenterContainer"> ·&nbsp; <a href="#" onclick="if(typeof window !== 'undefined' && window.truste && window.truste.eu && window.truste.eu.clickListener) { window.truste.eu.clickListener(); } return false;" style="cursor: pointer;">Manage Privacy Choices</a></span>
</div>`, </div>`,
}, },
], ],
}, },
], ],
}, },
algolia: {
appId: "SMEA51Q5OL",
// public key, safe to commit
apiKey: "b2ec302e9880e8979ad6a68f0c36271e",
indexName: "openrag-algolia",
contextualSearch: true,
searchParameters: {},
searchPagePath: "search",
},
prism: { prism: {
theme: prismThemes.github, theme: prismThemes.github,
darkTheme: prismThemes.dracula, darkTheme: prismThemes.dracula,

View file

@ -26,7 +26,7 @@
"typescript": "~5.9.3" "typescript": "~5.9.3"
}, },
"engines": { "engines": {
"node": ">=18.0" "node": ">=20.20.0"
} }
}, },
"node_modules/@ai-sdk/gateway": { "node_modules/@ai-sdk/gateway": {

View file

@ -46,6 +46,6 @@
] ]
}, },
"engines": { "engines": {
"node": ">=18.0" "node": ">=20.20.0"
} }
} }

View file

@ -75,6 +75,11 @@ const sidebars = {
label: "Chat", label: "Chat",
}, },
"reference/configuration", "reference/configuration",
{
type: "doc",
id: "reference/api-sdk-overview",
label: "APIs and SDKs",
},
"support/contribute", "support/contribute",
"support/troubleshoot", "support/troubleshoot",
], ],

View file

@ -2,6 +2,9 @@
"name": "frontend", "name": "frontend",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"engines": {
"node": ">=20.20.0"
},
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",

18
helm/openrag/Chart.yaml Normal file
View file

@ -0,0 +1,18 @@
apiVersion: v2
name: openrag
description: A Helm chart for deploying OpenRAG - an open-source agentic RAG platform
type: application
version: 0.1.0
appVersion: "0.1.52"
keywords:
- openrag
- rag
- langflow
- opensearch
- ai
- llm
home: https://github.com/langflow-ai/openrag
sources:
- https://github.com/langflow-ai/openrag
maintainers:
- name: OpenRAG Team

View file

@ -0,0 +1,80 @@
OpenRAG has been deployed successfully!
{{- if .Values.global.tenant.name }}
Tenant: {{ .Values.global.tenant.name }}
Namespace: {{ include "openrag.namespace" . }}
{{- end }}
=== Services Deployed ===
{{- if .Values.langflow.enabled }}
Langflow:
- Internal URL: http://{{ include "openrag.fullname" . }}-langflow:{{ .Values.langflow.service.port }}
{{- if and .Values.ingress.enabled .Values.ingress.hosts.langflow.enabled .Values.ingress.hosts.langflow.host }}
- External URL: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.ingress.hosts.langflow.host }}
{{- end }}
{{- end }}
{{- if .Values.backend.enabled }}
Backend API:
- Internal URL: http://{{ include "openrag.fullname" . }}-backend:{{ .Values.backend.service.port }}
{{- if and .Values.ingress.enabled .Values.ingress.hosts.backend.host }}
- External URL: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.ingress.hosts.backend.host }}
{{- end }}
{{- end }}
{{- if .Values.frontend.enabled }}
Frontend UI:
- Internal URL: http://{{ include "openrag.fullname" . }}-frontend:{{ .Values.frontend.service.port }}
{{- if and .Values.ingress.enabled .Values.ingress.hosts.frontend.host }}
- External URL: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.ingress.hosts.frontend.host }}
{{- end }}
{{- end }}
{{- if .Values.dashboards.enabled }}
OpenSearch Dashboards:
- Internal URL: http://{{ include "openrag.fullname" . }}-dashboards:{{ .Values.dashboards.service.port }}
{{- if and .Values.ingress.enabled .Values.ingress.hosts.dashboards.enabled .Values.ingress.hosts.dashboards.host }}
- External URL: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.ingress.hosts.dashboards.host }}
{{- end }}
{{- end }}
=== External Dependencies ===
OpenSearch (External SaaS):
- Host: {{ .Values.global.opensearch.host }}
- Port: {{ .Values.global.opensearch.port }}
- Scheme: {{ .Values.global.opensearch.scheme }}
=== Credentials ===
To retrieve the Langflow superuser credentials:
kubectl get secret {{ include "openrag.fullname" . }}-langflow -n {{ include "openrag.namespace" . }} -o jsonpath='{.data.superuser}' | base64 -d
kubectl get secret {{ include "openrag.fullname" . }}-langflow -n {{ include "openrag.namespace" . }} -o jsonpath='{.data.superuser-password}' | base64 -d
=== Quick Start ===
{{- if and .Values.ingress.enabled .Values.ingress.hosts.frontend.host }}
1. Access the OpenRAG UI at: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.ingress.hosts.frontend.host }}
{{- else }}
1. Port-forward the frontend service:
kubectl port-forward svc/{{ include "openrag.fullname" . }}-frontend {{ .Values.frontend.service.port }}:{{ .Values.frontend.service.port }} -n {{ include "openrag.namespace" . }}
Then access: http://localhost:{{ .Values.frontend.service.port }}
{{- end }}
2. Upload documents to your knowledge base
3. Start chatting with your documents using the AI-powered chat interface
=== Troubleshooting ===
Check pod status:
kubectl get pods -n {{ include "openrag.namespace" . }} -l app.kubernetes.io/instance={{ .Release.Name }}
Check pod logs:
kubectl logs -n {{ include "openrag.namespace" . }} -l app.kubernetes.io/component=langflow
kubectl logs -n {{ include "openrag.namespace" . }} -l app.kubernetes.io/component=backend
kubectl logs -n {{ include "openrag.namespace" . }} -l app.kubernetes.io/component=frontend
For more information, visit: https://github.com/langflow-ai/openrag

View file

@ -0,0 +1,163 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "openrag.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
If tenant name is provided, prefix with tenant name.
*/}}
{{- define "openrag.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if .Values.global.tenant.name }}
{{- printf "%s-%s" .Values.global.tenant.name $name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s" $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create the namespace name.
Uses tenant namespace if specified, otherwise tenant name, otherwise release namespace.
*/}}
{{- define "openrag.namespace" -}}
{{- if .Values.global.tenant.namespace }}
{{- .Values.global.tenant.namespace }}
{{- else if .Values.global.tenant.name }}
{{- .Values.global.tenant.name }}
{{- else }}
{{- .Release.Namespace }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "openrag.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "openrag.labels" -}}
helm.sh/chart: {{ include "openrag.chart" . }}
{{ include "openrag.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- if .Values.global.tenant.name }}
openrag.io/tenant: {{ .Values.global.tenant.name }}
{{- end }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "openrag.selectorLabels" -}}
app.kubernetes.io/name: {{ include "openrag.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "openrag.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "openrag.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Langflow component labels
*/}}
{{- define "openrag.langflow.labels" -}}
{{ include "openrag.labels" . }}
app.kubernetes.io/component: langflow
{{- end }}
{{/*
Langflow selector labels
*/}}
{{- define "openrag.langflow.selectorLabels" -}}
{{ include "openrag.selectorLabels" . }}
app.kubernetes.io/component: langflow
{{- end }}
{{/*
Backend component labels
*/}}
{{- define "openrag.backend.labels" -}}
{{ include "openrag.labels" . }}
app.kubernetes.io/component: backend
{{- end }}
{{/*
Backend selector labels
*/}}
{{- define "openrag.backend.selectorLabels" -}}
{{ include "openrag.selectorLabels" . }}
app.kubernetes.io/component: backend
{{- end }}
{{/*
Frontend component labels
*/}}
{{- define "openrag.frontend.labels" -}}
{{ include "openrag.labels" . }}
app.kubernetes.io/component: frontend
{{- end }}
{{/*
Frontend selector labels
*/}}
{{- define "openrag.frontend.selectorLabels" -}}
{{ include "openrag.selectorLabels" . }}
app.kubernetes.io/component: frontend
{{- end }}
{{/*
Dashboards component labels
*/}}
{{- define "openrag.dashboards.labels" -}}
{{ include "openrag.labels" . }}
app.kubernetes.io/component: dashboards
{{- end }}
{{/*
Dashboards selector labels
*/}}
{{- define "openrag.dashboards.selectorLabels" -}}
{{ include "openrag.selectorLabels" . }}
app.kubernetes.io/component: dashboards
{{- end }}
{{/*
Generate the Langflow service URL
*/}}
{{- define "openrag.langflow.url" -}}
http://{{ include "openrag.fullname" . }}-langflow:{{ .Values.langflow.service.port }}
{{- end }}
{{/*
Generate the Backend service URL
*/}}
{{- define "openrag.backend.url" -}}
http://{{ include "openrag.fullname" . }}-backend:{{ .Values.backend.service.port }}
{{- end }}
{{/*
Generate the OpenSearch URL
*/}}
{{- define "openrag.opensearch.url" -}}
{{ .Values.global.opensearch.scheme }}://{{ .Values.global.opensearch.host }}:{{ .Values.global.opensearch.port }}
{{- end }}

View file

@ -0,0 +1,273 @@
{{- if .Values.backend.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "openrag.fullname" . }}-backend
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.backend.labels" . | nindent 4 }}
spec:
replicas: 1 # Single pod for vertical scaling
strategy:
type: Recreate # Required for RWO PVCs
selector:
matchLabels:
{{- include "openrag.backend.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "openrag.backend.selectorLabels" . | nindent 8 }}
annotations:
checksum/secret-opensearch: {{ include (print $.Template.BasePath "/secrets/opensearch-secret.yaml") . | sha256sum }}
checksum/secret-langflow: {{ include (print $.Template.BasePath "/secrets/langflow-secret.yaml") . | sha256sum }}
checksum/config-flows: {{ include (print $.Template.BasePath "/configmaps/flow-ids-configmap.yaml") . | sha256sum }}
checksum/config-app: {{ include (print $.Template.BasePath "/configmaps/app-config-configmap.yaml") . | sha256sum }}
spec:
serviceAccountName: {{ include "openrag.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.langflow.enabled }}
initContainers:
- name: wait-for-langflow
image: busybox:1.36
command:
- sh
- -c
- |
echo "Waiting for Langflow to be ready..."
until nc -z {{ include "openrag.fullname" . }}-langflow {{ .Values.langflow.service.port }}; do
echo "Langflow not ready, sleeping 5s..."
sleep 5
done
echo "Langflow is ready!"
{{- end }}
containers:
- name: backend
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Values.global.imageTag }}"
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: 8000
protocol: TCP
env:
# OpenSearch connection (external SaaS)
- name: OPENSEARCH_HOST
value: {{ .Values.global.opensearch.host | quote }}
- name: OPENSEARCH_PORT
value: {{ .Values.global.opensearch.port | quote }}
- name: OPENSEARCH_USERNAME
value: {{ .Values.global.opensearch.username | quote }}
{{- if .Values.global.opensearch.password }}
- name: OPENSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-opensearch
key: password
{{- end }}
# Langflow connection
- name: LANGFLOW_URL
value: {{ include "openrag.langflow.url" . | quote }}
{{- if .Values.backend.langflowPublicUrl }}
- name: LANGFLOW_PUBLIC_URL
value: {{ .Values.backend.langflowPublicUrl | quote }}
{{- end }}
- name: LANGFLOW_AUTO_LOGIN
value: {{ .Values.langflow.auth.autoLogin | quote }}
- name: LANGFLOW_SUPERUSER
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-langflow
key: superuser
- name: LANGFLOW_SUPERUSER_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-langflow
key: superuser-password
# Flow IDs from ConfigMap
- name: LANGFLOW_CHAT_FLOW_ID
valueFrom:
configMapKeyRef:
name: {{ include "openrag.fullname" . }}-flow-ids
key: chat-flow-id
- name: LANGFLOW_INGEST_FLOW_ID
valueFrom:
configMapKeyRef:
name: {{ include "openrag.fullname" . }}-flow-ids
key: ingest-flow-id
- name: LANGFLOW_URL_INGEST_FLOW_ID
valueFrom:
configMapKeyRef:
name: {{ include "openrag.fullname" . }}-flow-ids
key: url-ingest-flow-id
- name: NUDGES_FLOW_ID
valueFrom:
configMapKeyRef:
name: {{ include "openrag.fullname" . }}-flow-ids
key: nudges-flow-id
# Feature flags
- name: DISABLE_INGEST_WITH_LANGFLOW
value: {{ .Values.backend.features.disableIngestWithLangflow | quote }}
# LLM Provider keys
{{- if .Values.llmProviders.openai.enabled }}
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: openai-api-key
{{- end }}
{{- if .Values.llmProviders.anthropic.enabled }}
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: anthropic-api-key
{{- end }}
{{- if .Values.llmProviders.watsonx.enabled }}
- name: WATSONX_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: watsonx-api-key
- name: WATSONX_ENDPOINT
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: watsonx-endpoint
- name: WATSONX_PROJECT_ID
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: watsonx-project-id
{{- end }}
{{- if .Values.llmProviders.ollama.enabled }}
- name: OLLAMA_ENDPOINT
value: {{ .Values.llmProviders.ollama.endpoint | quote }}
{{- end }}
# OAuth credentials
{{- if .Values.global.oauth.google.enabled }}
- name: GOOGLE_OAUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-oauth
key: google-client-id
- name: GOOGLE_OAUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-oauth
key: google-client-secret
{{- end }}
{{- if .Values.global.oauth.microsoft.enabled }}
- name: MICROSOFT_GRAPH_OAUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-oauth
key: microsoft-client-id
- name: MICROSOFT_GRAPH_OAUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-oauth
key: microsoft-client-secret
{{- end }}
# AWS credentials
{{- if .Values.backend.aws.enabled }}
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-aws
key: access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-aws
key: secret-access-key
{{- end }}
# Webhook configuration
{{- if .Values.backend.webhook.enabled }}
- name: WEBHOOK_BASE_URL
value: {{ .Values.backend.webhook.baseUrl | quote }}
{{- end }}
volumeMounts:
{{- if .Values.backend.persistence.documents.enabled }}
- name: documents
mountPath: {{ .Values.backend.persistence.documents.mountPath }}
{{- end }}
{{- if .Values.backend.persistence.keys.enabled }}
- name: keys
mountPath: {{ .Values.backend.persistence.keys.mountPath }}
{{- end }}
{{- if .Values.backend.persistence.config.enabled }}
- name: config
mountPath: {{ .Values.backend.persistence.config.mountPath }}
{{- end }}
{{- if .Values.langflow.persistence.enabled }}
- name: flows
mountPath: /app/flows
subPath: {{ .Values.langflow.persistence.flowsSubPath }}
readOnly: true
{{- end }}
resources:
{{- toYaml .Values.backend.resources | nindent 12 }}
{{- if .Values.backend.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: {{ .Values.backend.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.backend.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.backend.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.backend.livenessProbe.failureThreshold }}
{{- end }}
{{- if .Values.backend.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: {{ .Values.backend.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.backend.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.backend.readinessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.backend.readinessProbe.failureThreshold }}
{{- end }}
volumes:
{{- if .Values.backend.persistence.documents.enabled }}
- name: documents
persistentVolumeClaim:
claimName: {{ include "openrag.fullname" . }}-documents
{{- end }}
{{- if .Values.backend.persistence.keys.enabled }}
- name: keys
persistentVolumeClaim:
claimName: {{ include "openrag.fullname" . }}-keys
{{- end }}
{{- if .Values.backend.persistence.config.enabled }}
- name: config
persistentVolumeClaim:
claimName: {{ include "openrag.fullname" . }}-config
{{- end }}
{{- if .Values.langflow.persistence.enabled }}
- name: flows
persistentVolumeClaim:
claimName: {{ include "openrag.fullname" . }}-langflow
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if .Values.backend.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "openrag.fullname" . }}-backend
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.backend.labels" . | nindent 4 }}
spec:
type: {{ .Values.backend.service.type }}
ports:
- port: {{ .Values.backend.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "openrag.backend.selectorLabels" . | nindent 4 }}
{{- end }}

View file

@ -0,0 +1,39 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "openrag.fullname" . }}-app-config
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
data:
config.yaml: |
agent:
llm_model: {{ .Values.appConfig.agent.llmModel | quote }}
llm_provider: {{ .Values.appConfig.agent.llmProvider | quote }}
{{- if .Values.appConfig.agent.systemPrompt }}
system_prompt: {{ .Values.appConfig.agent.systemPrompt | quote }}
{{- end }}
edited: false
knowledge:
chunk_overlap: {{ .Values.appConfig.knowledge.chunkOverlap }}
chunk_size: {{ .Values.appConfig.knowledge.chunkSize }}
embedding_model: {{ .Values.appConfig.knowledge.embeddingModel | quote }}
embedding_provider: {{ .Values.appConfig.knowledge.embeddingProvider | quote }}
ocr: {{ .Values.appConfig.knowledge.ocr }}
picture_descriptions: {{ .Values.appConfig.knowledge.pictureDescriptions }}
table_structure: {{ .Values.appConfig.knowledge.tableStructure }}
providers:
anthropic:
configured: {{ .Values.llmProviders.anthropic.enabled }}
ollama:
configured: {{ .Values.llmProviders.ollama.enabled }}
{{- if .Values.llmProviders.ollama.endpoint }}
endpoint: {{ .Values.llmProviders.ollama.endpoint | quote }}
{{- end }}
openai:
configured: {{ .Values.llmProviders.openai.enabled }}
watsonx:
configured: {{ .Values.llmProviders.watsonx.enabled }}
{{- if .Values.llmProviders.watsonx.endpoint }}
endpoint: {{ .Values.llmProviders.watsonx.endpoint | quote }}
{{- end }}

View file

@ -0,0 +1,14 @@
{{- if .Values.langflow.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "openrag.fullname" . }}-flow-ids
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
data:
chat-flow-id: {{ .Values.langflow.flows.chatFlowId | quote }}
ingest-flow-id: {{ .Values.langflow.flows.ingestFlowId | quote }}
url-ingest-flow-id: {{ .Values.langflow.flows.urlIngestFlowId | quote }}
nudges-flow-id: {{ .Values.langflow.flows.nudgesFlowId | quote }}
{{- end }}

View file

@ -0,0 +1,12 @@
{{- if .Values.langflow.flows.loadDefaults }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "openrag.fullname" . }}-flow-agent
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
data:
openrag_agent.json: |-
{{ .Files.Get "flows/openrag_agent.json" | indent 4 }}
{{- end }}

View file

@ -0,0 +1,12 @@
{{- if .Values.langflow.flows.loadDefaults }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "openrag.fullname" . }}-flow-ingestion
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
data:
ingestion_flow.json: |-
{{ .Files.Get "flows/ingestion_flow.json" | indent 4 }}
{{- end }}

View file

@ -0,0 +1,12 @@
{{- if .Values.langflow.flows.loadDefaults }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "openrag.fullname" . }}-flow-nudges
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
data:
openrag_nudges.json: |-
{{ .Files.Get "flows/openrag_nudges.json" | indent 4 }}
{{- end }}

View file

@ -0,0 +1,12 @@
{{- if .Values.langflow.flows.loadDefaults }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "openrag.fullname" . }}-flow-url
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
data:
openrag_url_mcp.json: |-
{{ .Files.Get "flows/openrag_url_mcp.json" | indent 4 }}
{{- end }}

View file

@ -0,0 +1,81 @@
{{- if .Values.dashboards.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "openrag.fullname" . }}-dashboards
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.dashboards.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.dashboards.replicaCount }}
selector:
matchLabels:
{{- include "openrag.dashboards.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "openrag.dashboards.selectorLabels" . | nindent 8 }}
annotations:
checksum/secret: {{ include (print $.Template.BasePath "/secrets/opensearch-secret.yaml") . | sha256sum }}
spec:
serviceAccountName: {{ include "openrag.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: dashboards
image: "{{ .Values.dashboards.image.repository }}:{{ .Values.dashboards.image.tag }}"
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
ports:
- name: http
containerPort: 5601
protocol: TCP
env:
# OpenSearch connection (external SaaS)
- name: OPENSEARCH_HOSTS
value: '["{{ include "openrag.opensearch.url" . }}"]'
- name: OPENSEARCH_USERNAME
value: {{ .Values.global.opensearch.username | quote }}
{{- if .Values.global.opensearch.password }}
- name: OPENSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-opensearch
key: password
{{- end }}
resources:
{{- toYaml .Values.dashboards.resources | nindent 12 }}
{{- if .Values.dashboards.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: /api/status
port: http
initialDelaySeconds: {{ .Values.dashboards.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.dashboards.livenessProbe.periodSeconds }}
{{- end }}
{{- if .Values.dashboards.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: /api/status
port: http
initialDelaySeconds: {{ .Values.dashboards.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.dashboards.readinessProbe.periodSeconds }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if .Values.dashboards.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "openrag.fullname" . }}-dashboards
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.dashboards.labels" . | nindent 4 }}
spec:
type: {{ .Values.dashboards.service.type }}
ports:
- port: {{ .Values.dashboards.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "openrag.dashboards.selectorLabels" . | nindent 4 }}
{{- end }}

View file

@ -0,0 +1,80 @@
{{- if .Values.frontend.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "openrag.fullname" . }}-frontend
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.frontend.labels" . | nindent 4 }}
spec:
{{- if not .Values.frontend.autoscaling.enabled }}
replicas: {{ .Values.frontend.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "openrag.frontend.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "openrag.frontend.selectorLabels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "openrag.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: frontend
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Values.global.imageTag }}"
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: 3000
protocol: TCP
env:
# Backend connection (uses internal service name)
- name: OPENRAG_BACKEND_HOST
value: "{{ include "openrag.fullname" . }}-backend"
resources:
{{- toYaml .Values.frontend.resources | nindent 12 }}
{{- if .Values.frontend.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: {{ .Values.frontend.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.frontend.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.frontend.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.frontend.livenessProbe.failureThreshold }}
{{- end }}
{{- if .Values.frontend.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: {{ .Values.frontend.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.frontend.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.frontend.readinessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.frontend.readinessProbe.failureThreshold }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,33 @@
{{- if and .Values.frontend.enabled .Values.frontend.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "openrag.fullname" . }}-frontend
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.frontend.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "openrag.fullname" . }}-frontend
minReplicas: {{ .Values.frontend.autoscaling.minReplicas }}
maxReplicas: {{ .Values.frontend.autoscaling.maxReplicas }}
metrics:
{{- if .Values.frontend.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.frontend.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.frontend.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.frontend.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if .Values.frontend.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "openrag.fullname" . }}-frontend
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.frontend.labels" . | nindent 4 }}
spec:
type: {{ .Values.frontend.service.type }}
ports:
- port: {{ .Values.frontend.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "openrag.frontend.selectorLabels" . | nindent 4 }}
{{- end }}

View file

@ -0,0 +1,104 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "openrag.fullname" . }}
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- if .Values.ingress.tls.certManager.enabled }}
cert-manager.io/cluster-issuer: {{ .Values.ingress.tls.certManager.issuerRef.name }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls.enabled }}
tls:
{{- if .Values.ingress.hosts.frontend.host }}
- hosts:
- {{ .Values.ingress.hosts.frontend.host }}
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-frontend-tls" (include "openrag.fullname" .)) }}
{{- end }}
{{- if .Values.ingress.hosts.backend.host }}
- hosts:
- {{ .Values.ingress.hosts.backend.host }}
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-backend-tls" (include "openrag.fullname" .)) }}
{{- end }}
{{- if and .Values.ingress.hosts.langflow.enabled .Values.ingress.hosts.langflow.host }}
- hosts:
- {{ .Values.ingress.hosts.langflow.host }}
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-langflow-tls" (include "openrag.fullname" .)) }}
{{- end }}
{{- if and .Values.dashboards.enabled .Values.ingress.hosts.dashboards.enabled .Values.ingress.hosts.dashboards.host }}
- hosts:
- {{ .Values.ingress.hosts.dashboards.host }}
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-dashboards-tls" (include "openrag.fullname" .)) }}
{{- end }}
{{- end }}
rules:
{{- if .Values.ingress.hosts.frontend.host }}
# Frontend ingress rule
- host: {{ .Values.ingress.hosts.frontend.host }}
http:
paths:
{{- range .Values.ingress.hosts.frontend.paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "openrag.fullname" $ }}-frontend
port:
number: {{ $.Values.frontend.service.port }}
{{- end }}
{{- end }}
{{- if .Values.ingress.hosts.backend.host }}
# Backend API ingress rule
- host: {{ .Values.ingress.hosts.backend.host }}
http:
paths:
{{- range .Values.ingress.hosts.backend.paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "openrag.fullname" $ }}-backend
port:
number: {{ $.Values.backend.service.port }}
{{- end }}
{{- end }}
{{- if and .Values.ingress.hosts.langflow.enabled .Values.ingress.hosts.langflow.host }}
# Optional Langflow direct access
- host: {{ .Values.ingress.hosts.langflow.host }}
http:
paths:
{{- range .Values.ingress.hosts.langflow.paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "openrag.fullname" $ }}-langflow
port:
number: {{ $.Values.langflow.service.port }}
{{- end }}
{{- end }}
{{- if and .Values.dashboards.enabled .Values.ingress.hosts.dashboards.enabled .Values.ingress.hosts.dashboards.host }}
# Optional Dashboards access
- host: {{ .Values.ingress.hosts.dashboards.host }}
http:
paths:
{{- range .Values.ingress.hosts.dashboards.paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "openrag.fullname" $ }}-dashboards
port:
number: {{ $.Values.dashboards.service.port }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,247 @@
{{- if .Values.langflow.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "openrag.fullname" . }}-langflow
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.langflow.labels" . | nindent 4 }}
spec:
replicas: 1 # Always 1 for SQLite-based Langflow
strategy:
type: Recreate # Required for RWO PVC
selector:
matchLabels:
{{- include "openrag.langflow.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "openrag.langflow.selectorLabels" . | nindent 8 }}
annotations:
checksum/secret: {{ include (print $.Template.BasePath "/secrets/langflow-secret.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmaps/flow-ids-configmap.yaml") . | sha256sum }}
spec:
serviceAccountName: {{ include "openrag.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.langflow.flows.loadDefaults }}
initContainers:
- name: load-default-flows
image: busybox:1.36
command:
- /bin/sh
- -c
- |
FLOWS_DIR="{{ .Values.langflow.persistence.mountPath }}/{{ .Values.langflow.persistence.flowsSubPath }}"
mkdir -p "$FLOWS_DIR"
if [ -z "$(ls -A $FLOWS_DIR 2>/dev/null)" ]; then
echo "Loading default flows..."
cp /default-flows/*.json "$FLOWS_DIR/"
echo "Flows loaded: $(ls $FLOWS_DIR)"
else
echo "Flows already exist, skipping."
fi
volumeMounts:
- name: langflow-data
mountPath: {{ .Values.langflow.persistence.mountPath }}
- name: default-flows
mountPath: /default-flows
{{- end }}
containers:
- name: langflow
image: "{{ .Values.langflow.image.repository }}:{{ .Values.langflow.image.tag | default .Values.global.imageTag }}"
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: 7860
protocol: TCP
env:
# Langflow core settings
- name: LANGFLOW_LOAD_FLOWS_PATH
value: {{ .Values.langflow.persistence.mountPath }}/{{ .Values.langflow.persistence.flowsSubPath }}
- name: LANGFLOW_DATABASE_URL
value: "sqlite:///{{ .Values.langflow.persistence.mountPath }}/{{ .Values.langflow.persistence.dbSubPath }}"
- name: LANGFLOW_DEACTIVATE_TRACING
value: {{ .Values.langflow.deactivateTracing | quote }}
- name: LANGFLOW_LOG_LEVEL
value: {{ .Values.langflow.logLevel | quote }}
- name: HIDE_GETTING_STARTED_PROGRESS
value: "true"
# Auth settings
- name: LANGFLOW_AUTO_LOGIN
value: {{ .Values.langflow.auth.autoLogin | quote }}
- name: LANGFLOW_NEW_USER_IS_ACTIVE
value: {{ .Values.langflow.auth.newUserIsActive | quote }}
- name: LANGFLOW_ENABLE_SUPERUSER_CLI
value: {{ .Values.langflow.auth.enableSuperuserCli | quote }}
# Variables to expose to flows
- name: LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT
value: {{ .Values.langflow.variablesToGetFromEnvironment | quote }}
# Flow context variables (defaults for flow execution)
- name: JWT
value: "None"
- name: OWNER
value: "None"
- name: OWNER_NAME
value: "None"
- name: OWNER_EMAIL
value: "None"
- name: CONNECTOR_TYPE
value: "system"
- name: CONNECTOR_TYPE_URL
value: "url"
- name: OPENRAG-QUERY-FILTER
value: "{}"
- name: FILENAME
value: "None"
- name: MIMETYPE
value: "None"
- name: FILESIZE
value: "0"
- name: SELECTED_EMBEDDING_MODEL
value: ""
# Secrets from langflow secret
- name: LANGFLOW_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-langflow
key: secret-key
- name: LANGFLOW_SUPERUSER
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-langflow
key: superuser
- name: LANGFLOW_SUPERUSER_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-langflow
key: superuser-password
# OpenSearch password (for flows)
{{- if .Values.global.opensearch.password }}
- name: OPENSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-opensearch
key: password
{{- end }}
# LLM Provider keys
{{- if .Values.llmProviders.openai.enabled }}
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: openai-api-key
{{- else }}
- name: OPENAI_API_KEY
value: "None"
{{- end }}
{{- if .Values.llmProviders.anthropic.enabled }}
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: anthropic-api-key
{{- else }}
- name: ANTHROPIC_API_KEY
value: "None"
{{- end }}
{{- if .Values.llmProviders.watsonx.enabled }}
- name: WATSONX_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: watsonx-api-key
- name: WATSONX_ENDPOINT
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: watsonx-endpoint
- name: WATSONX_PROJECT_ID
valueFrom:
secretKeyRef:
name: {{ include "openrag.fullname" . }}-llm-providers
key: watsonx-project-id
{{- else }}
- name: WATSONX_API_KEY
value: "None"
- name: WATSONX_ENDPOINT
value: "None"
- name: WATSONX_PROJECT_ID
value: "None"
{{- end }}
{{- if .Values.llmProviders.ollama.enabled }}
- name: OLLAMA_BASE_URL
value: {{ .Values.llmProviders.ollama.endpoint | quote }}
{{- else }}
- name: OLLAMA_BASE_URL
value: "None"
{{- end }}
volumeMounts:
- name: langflow-data
mountPath: {{ .Values.langflow.persistence.mountPath }}
resources:
{{- toYaml .Values.langflow.resources | nindent 12 }}
{{- if .Values.langflow.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: {{ .Values.langflow.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.langflow.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.langflow.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.langflow.livenessProbe.failureThreshold }}
{{- end }}
{{- if .Values.langflow.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: {{ .Values.langflow.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.langflow.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.langflow.readinessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.langflow.readinessProbe.failureThreshold }}
{{- end }}
volumes:
- name: langflow-data
{{- if .Values.langflow.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "openrag.fullname" . }}-langflow
{{- else }}
emptyDir: {}
{{- end }}
{{- if .Values.langflow.flows.loadDefaults }}
- name: default-flows
projected:
sources:
- configMap:
name: {{ include "openrag.fullname" . }}-flow-ingestion
- configMap:
name: {{ include "openrag.fullname" . }}-flow-agent
- configMap:
name: {{ include "openrag.fullname" . }}-flow-nudges
- configMap:
name: {{ include "openrag.fullname" . }}-flow-url
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if .Values.langflow.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "openrag.fullname" . }}-langflow
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.langflow.labels" . | nindent 4 }}
spec:
type: {{ .Values.langflow.service.type }}
ports:
- port: {{ .Values.langflow.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "openrag.langflow.selectorLabels" . | nindent 4 }}
{{- end }}

View file

@ -0,0 +1,13 @@
{{- if .Values.backend.aws.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "openrag.fullname" . }}-aws
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
type: Opaque
stringData:
access-key-id: {{ .Values.backend.aws.accessKeyId | quote }}
secret-access-key: {{ .Values.backend.aws.secretAccessKey | quote }}
{{- end }}

View file

@ -0,0 +1,14 @@
{{- if .Values.langflow.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "openrag.fullname" . }}-langflow
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
type: Opaque
stringData:
secret-key: {{ .Values.langflow.auth.secretKey | default (randAlphaNum 32) | quote }}
superuser: {{ .Values.langflow.auth.superuser | quote }}
superuser-password: {{ .Values.langflow.auth.superuserPassword | default (randAlphaNum 16) | quote }}
{{- end }}

View file

@ -0,0 +1,22 @@
{{- if or .Values.llmProviders.openai.enabled .Values.llmProviders.anthropic.enabled .Values.llmProviders.watsonx.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "openrag.fullname" . }}-llm-providers
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
type: Opaque
stringData:
{{- if .Values.llmProviders.openai.enabled }}
openai-api-key: {{ .Values.llmProviders.openai.apiKey | quote }}
{{- end }}
{{- if .Values.llmProviders.anthropic.enabled }}
anthropic-api-key: {{ .Values.llmProviders.anthropic.apiKey | quote }}
{{- end }}
{{- if .Values.llmProviders.watsonx.enabled }}
watsonx-api-key: {{ .Values.llmProviders.watsonx.apiKey | quote }}
watsonx-endpoint: {{ .Values.llmProviders.watsonx.endpoint | quote }}
watsonx-project-id: {{ .Values.llmProviders.watsonx.projectId | quote }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,19 @@
{{- if or .Values.global.oauth.google.enabled .Values.global.oauth.microsoft.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "openrag.fullname" . }}-oauth
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
type: Opaque
stringData:
{{- if .Values.global.oauth.google.enabled }}
google-client-id: {{ .Values.global.oauth.google.clientId | quote }}
google-client-secret: {{ .Values.global.oauth.google.clientSecret | quote }}
{{- end }}
{{- if .Values.global.oauth.microsoft.enabled }}
microsoft-client-id: {{ .Values.global.oauth.microsoft.clientId | quote }}
microsoft-client-secret: {{ .Values.global.oauth.microsoft.clientSecret | quote }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,13 @@
{{- if .Values.global.opensearch.password }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "openrag.fullname" . }}-opensearch
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
type: Opaque
stringData:
password: {{ .Values.global.opensearch.password | quote }}
username: {{ .Values.global.opensearch.username | quote }}
{{- end }}

View file

@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "openrag.serviceAccountName" . }}
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if and .Values.backend.enabled .Values.backend.persistence.config.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "openrag.fullname" . }}-config
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.backend.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.backend.persistence.config.accessMode }}
{{- if .Values.backend.persistence.config.storageClass }}
storageClassName: {{ .Values.backend.persistence.config.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.backend.persistence.config.size }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if and .Values.backend.enabled .Values.backend.persistence.documents.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "openrag.fullname" . }}-documents
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.backend.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.backend.persistence.documents.accessMode }}
{{- if .Values.backend.persistence.documents.storageClass }}
storageClassName: {{ .Values.backend.persistence.documents.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.backend.persistence.documents.size }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if and .Values.backend.enabled .Values.backend.persistence.keys.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "openrag.fullname" . }}-keys
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.backend.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.backend.persistence.keys.accessMode }}
{{- if .Values.backend.persistence.keys.storageClass }}
storageClassName: {{ .Values.backend.persistence.keys.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.backend.persistence.keys.size }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if and .Values.langflow.enabled .Values.langflow.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "openrag.fullname" . }}-langflow
namespace: {{ include "openrag.namespace" . }}
labels:
{{- include "openrag.langflow.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.langflow.persistence.accessMode }}
{{- if .Values.langflow.persistence.storageClass }}
storageClassName: {{ .Values.langflow.persistence.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.langflow.persistence.size }}
{{- end }}

408
helm/openrag/values.yaml Normal file
View file

@ -0,0 +1,408 @@
# OpenRAG Helm Chart Values
# This chart deploys OpenRAG with external OpenSearch SaaS connection
# Override names
nameOverride: ""
fullnameOverride: ""
# Global settings
global:
# Tenant identification - used for resource naming and namespace
tenant:
name: "" # Required for multi-tenant: tenant identifier (e.g., "acme")
namespace: "" # Optional: override namespace (defaults to tenant name or release namespace)
# Image settings
imageRegistry: "langflowai"
imagePullPolicy: IfNotPresent
imageTag: "latest" # Override with specific version in production
imagePullSecrets: []
# External OpenSearch SaaS connection (OpenSearch is NOT deployed by this chart)
opensearch:
host: "" # Required: OpenSearch SaaS endpoint (e.g., "my-cluster.us-east-1.es.amazonaws.com")
port: 443 # Default HTTPS port for managed OpenSearch
scheme: "https" # https for production SaaS
username: "admin" # OpenSearch username
password: "" # OpenSearch password (stored in secret)
# Shared OAuth credentials (same across all tenants)
oauth:
google:
enabled: false
clientId: "" # Google OAuth client ID
clientSecret: "" # Google OAuth client secret
microsoft:
enabled: false
clientId: "" # Microsoft Graph OAuth client ID
clientSecret: "" # Microsoft Graph OAuth client secret
# ============================================================================
# Langflow Configuration
# ============================================================================
langflow:
enabled: true
image:
repository: langflowai/openrag-langflow
tag: "" # Uses global.imageTag if empty
# Single pod - vertical scaling only (SQLite requires single writer)
replicaCount: 1
# Resource requests/limits for vertical scaling
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "4"
memory: "8Gi"
# Persistence for SQLite DB and flows
persistence:
enabled: true
storageClass: "" # Empty uses cluster default
accessMode: ReadWriteOnce
size: 10Gi
mountPath: /app/data
flowsSubPath: flows
dbSubPath: langflow.db
# Flow configuration (UUIDs for Langflow workflows)
flows:
loadDefaults: true # Load default OpenRAG flows on first deployment
chatFlowId: "1098eea1-6649-4e1d-aed1-b77249fb8dd0"
ingestFlowId: "5488df7c-b93f-4f87-a446-b67028bc0813"
urlIngestFlowId: "72c3d17c-2dac-4a73-b48a-6518473d7830"
nudgesFlowId: "ebc01d31-1976-46ce-a385-b0240327226c"
loadPath: /app/flows
# Authentication settings
auth:
autoLogin: false
superuser: "admin" # Langflow superuser username
superuserPassword: "" # Langflow superuser password (stored in secret)
secretKey: "" # Langflow secret key for JWT (stored in secret)
newUserIsActive: false
enableSuperuserCli: false
# Runtime settings
deactivateTracing: true
logLevel: "INFO" # DEBUG, INFO, WARNING, ERROR
# Variables to expose to flows
variablesToGetFromEnvironment: "JWT,OPENRAG-QUERY-FILTER,OPENSEARCH_PASSWORD,OWNER,OWNER_NAME,OWNER_EMAIL,CONNECTOR_TYPE,FILENAME,MIMETYPE,FILESIZE,SELECTED_EMBEDDING_MODEL,OPENAI_API_KEY,ANTHROPIC_API_KEY,WATSONX_API_KEY,WATSONX_ENDPOINT,WATSONX_PROJECT_ID,OLLAMA_BASE_URL"
# Probes
livenessProbe:
enabled: true
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
enabled: true
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Service configuration
service:
type: ClusterIP
port: 7860
# ============================================================================
# OpenRAG Backend Configuration
# ============================================================================
backend:
enabled: true
image:
repository: langflowai/openrag-backend
tag: "" # Uses global.imageTag if empty
# Single pod for vertical scaling
replicaCount: 1
# Resource requests/limits
resources:
requests:
cpu: "500m"
memory: "2Gi"
limits:
cpu: "4"
memory: "16Gi"
# Persistence for documents, keys, and config
persistence:
documents:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 50Gi
mountPath: /app/openrag-documents
keys:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
mountPath: /app/keys
config:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
mountPath: /app/config
# Feature flags
features:
disableIngestWithLangflow: false # Set true to use traditional processor instead of Langflow
# Langflow public URL (for UI links to Langflow)
langflowPublicUrl: "" # e.g., "https://langflow.example.com"
# Webhook configuration for continuous ingestion
webhook:
enabled: false
baseUrl: "" # DNS routable URL for webhooks (e.g., ngrok URL)
# AWS credentials for S3 integration
aws:
enabled: false
accessKeyId: ""
secretAccessKey: ""
# Probes
livenessProbe:
enabled: true
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
enabled: true
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Service configuration
service:
type: ClusterIP
port: 8000
# ============================================================================
# OpenRAG Frontend Configuration
# ============================================================================
frontend:
enabled: true
image:
repository: langflowai/openrag-frontend
tag: "" # Uses global.imageTag if empty
# Can be multiple replicas (stateless)
replicaCount: 2
# Resource requests/limits
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
# Horizontal Pod Autoscaler
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# Probes
livenessProbe:
enabled: true
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
enabled: true
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Service configuration
service:
type: ClusterIP
port: 3000
# ============================================================================
# OpenSearch Dashboards Configuration (Optional)
# ============================================================================
dashboards:
enabled: false # Enable only if dashboards available in OS SaaS
image:
repository: opensearchproject/opensearch-dashboards
tag: "3.0.0"
replicaCount: 1
# Resource requests/limits
resources:
requests:
cpu: "100m"
memory: "512Mi"
limits:
cpu: "1"
memory: "2Gi"
# Probes
livenessProbe:
enabled: true
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
enabled: true
initialDelaySeconds: 30
periodSeconds: 10
# Service configuration
service:
type: ClusterIP
port: 5601
# ============================================================================
# Ingress Configuration
# ============================================================================
ingress:
enabled: true
className: "nginx" # nginx, alb, traefik, etc.
# Annotations for ingress controller
annotations: {}
# For nginx:
# nginx.ingress.kubernetes.io/proxy-body-size: "100m"
# nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
# For AWS ALB:
# alb.ingress.kubernetes.io/scheme: internet-facing
# alb.ingress.kubernetes.io/target-type: ip
# Host configuration
hosts:
frontend:
host: "" # e.g., "openrag.example.com"
paths:
- path: /
pathType: Prefix
backend:
host: "" # e.g., "api.openrag.example.com"
paths:
- path: /
pathType: Prefix
langflow:
enabled: false # Optional: expose Langflow directly
host: "" # e.g., "langflow.openrag.example.com"
paths:
- path: /
pathType: Prefix
dashboards:
enabled: false # Only if dashboards.enabled is true
host: ""
paths:
- path: /
pathType: Prefix
# TLS configuration
tls:
enabled: false
# Use existing secret:
# secretName: "openrag-tls"
# Or use cert-manager:
certManager:
enabled: false
issuerRef:
name: "letsencrypt-prod"
kind: "ClusterIssuer"
# ============================================================================
# LLM Provider API Keys
# ============================================================================
llmProviders:
openai:
enabled: false
apiKey: "" # OpenAI API key (stored in secret)
anthropic:
enabled: false
apiKey: "" # Anthropic API key (stored in secret)
watsonx:
enabled: false
apiKey: "" # WatsonX API key (stored in secret)
endpoint: "https://us-south.ml.cloud.ibm.com"
projectId: "" # WatsonX project ID
ollama:
enabled: false
endpoint: "" # Ollama endpoint URL (e.g., "http://ollama:11434")
# ============================================================================
# Application Config (config.yaml contents)
# ============================================================================
appConfig:
agent:
llmModel: "claude-sonnet-4-5-20250929"
llmProvider: "anthropic"
# System prompt can be customized here
systemPrompt: "" # Leave empty to use default
knowledge:
chunkOverlap: 200
chunkSize: 1000
embeddingModel: "text-embedding-3-large"
embeddingProvider: "openai"
ocr: false
pictureDescriptions: false
tableStructure: true
# ============================================================================
# Service Account
# ============================================================================
serviceAccount:
create: true
name: ""
annotations: {}
# ============================================================================
# Pod Security
# ============================================================================
podSecurityContext:
fsGroup: 1000
runAsNonRoot: true
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
runAsUser: 1000
runAsGroup: 1000
# ============================================================================
# Node Placement
# ============================================================================
nodeSelector: {}
tolerations: []
affinity: {}
# ============================================================================
# Pod Disruption Budgets
# ============================================================================
podDisruptionBudget:
enabled: false
minAvailable: 1
# maxUnavailable: 1

View file

@ -1,5 +1,6 @@
"""Docling service proxy endpoints.""" """Docling service proxy endpoints."""
import os
import socket import socket
import struct import struct
from pathlib import Path from pathlib import Path
@ -73,9 +74,15 @@ def determine_docling_host() -> str:
return "localhost" return "localhost"
# Detect the host IP once at startup # Use explicit URL if provided, otherwise auto-detect host
HOST_IP = determine_docling_host() _docling_url_override = os.getenv("DOCLING_SERVE_URL")
DOCLING_SERVICE_URL = f"http://{HOST_IP}:5001" if _docling_url_override:
DOCLING_SERVICE_URL = _docling_url_override.rstrip("/")
HOST_IP = _docling_url_override # For display in health responses
logger.info("Using DOCLING_SERVE_URL override: %s", DOCLING_SERVICE_URL)
else:
HOST_IP = determine_docling_host()
DOCLING_SERVICE_URL = f"http://{HOST_IP}:5001"
async def health(request: Request) -> JSONResponse: async def health(request: Request) -> JSONResponse:

View file

@ -21,6 +21,7 @@ from functools import partial
from starlette.applications import Starlette from starlette.applications import Starlette
from starlette.routing import Route from starlette.routing import Route
from starlette.responses import JSONResponse
# Set multiprocessing start method to 'spawn' for CUDA compatibility # Set multiprocessing start method to 'spawn' for CUDA compatibility
multiprocessing.set_start_method("spawn", force=True) multiprocessing.set_start_method("spawn", force=True)
@ -456,6 +457,24 @@ async def _ingest_default_documents_langflow(services, file_paths):
file_count=len(file_paths), file_count=len(file_paths),
) )
async def opensearch_health_ready(request):
"""Readiness probe: verifies OpenSearch dependency is reachable."""
try:
# Fast check that the cluster is reachable/auth works
await asyncio.wait_for(clients.opensearch.info(), timeout=5.0)
return JSONResponse(
{"status": "ready", "dependencies": {"opensearch": "up"}},
status_code=200,
)
except Exception as e:
return JSONResponse(
{
"status": "not_ready",
"dependencies": {"opensearch": "down"},
"error": str(e),
},
status_code=503,
)
async def _ingest_default_documents_openrag(services, file_paths): async def _ingest_default_documents_openrag(services, file_paths):
"""Ingest default documents using traditional OpenRAG processor.""" """Ingest default documents using traditional OpenRAG processor."""
@ -1148,6 +1167,11 @@ async def create_app():
), ),
methods=["GET"], methods=["GET"],
), ),
Route(
"/search/health",
opensearch_health_ready,
methods=["GET"],
),
# Models endpoints # Models endpoints
Route( Route(
"/models/openai", "/models/openai",

View file

@ -1,5 +1,7 @@
"""Main TUI application for OpenRAG.""" """Main TUI application for OpenRAG."""
import os
import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Iterable, Optional from typing import Iterable, Optional
@ -683,6 +685,51 @@ def migrate_legacy_data_directories():
logger.info("Data migration completed successfully") logger.info("Data migration completed successfully")
def generate_jwt_keys(keys_dir: Path):
"""Generate RSA keys for JWT signing if they don't exist.
This pre-generates keys on the host so containers can read them,
avoiding permission issues with Podman rootless mode.
"""
private_key_path = keys_dir / "private_key.pem"
public_key_path = keys_dir / "public_key.pem"
if private_key_path.exists() and public_key_path.exists():
logger.debug("JWT keys already exist")
return
try:
# Generate private key
subprocess.run(
["openssl", "genrsa", "-out", str(private_key_path), "2048"],
check=True,
capture_output=True,
)
# Set restrictive permissions on private key (readable by owner only)
os.chmod(private_key_path, 0o600)
# Generate public key from private key
subprocess.run(
[
"openssl",
"rsa",
"-in", str(private_key_path),
"-pubout",
"-out", str(public_key_path),
],
check=True,
capture_output=True,
)
# Set permissions on public key (readable by all)
os.chmod(public_key_path, 0o644)
logger.info("Generated RSA keys for JWT signing")
except FileNotFoundError:
logger.warning("openssl not found, skipping JWT key generation (will be generated in container)")
except subprocess.CalledProcessError as e:
logger.error(f"Failed to generate RSA keys: {e}")
def setup_host_directories(): def setup_host_directories():
"""Initialize OpenRAG directory structure on the host. """Initialize OpenRAG directory structure on the host.
@ -703,11 +750,14 @@ def setup_host_directories():
base_dir / "data", base_dir / "data",
base_dir / "data" / "opensearch-data", base_dir / "data" / "opensearch-data",
] ]
for directory in directories: for directory in directories:
directory.mkdir(parents=True, exist_ok=True) directory.mkdir(parents=True, exist_ok=True)
logger.debug(f"Ensured directory exists: {directory}") logger.debug(f"Ensured directory exists: {directory}")
# Generate JWT keys on host to avoid container permission issues
generate_jwt_keys(base_dir / "keys")
def run_tui(): def run_tui():
"""Run the OpenRAG TUI application.""" """Run the OpenRAG TUI application."""