diff --git a/.github/workflows/build-langflow-responses.yml b/.github/workflows/build-langflow-responses.yml index 8d9264e2..0f9d3d08 100644 --- a/.github/workflows/build-langflow-responses.yml +++ b/.github/workflows/build-langflow-responses.yml @@ -19,11 +19,8 @@ jobs: runs-on: ${{ matrix.runs-on }} steps: - - name: Checkout langflow load_flows_autologin_false branch + - name: Checkout uses: actions/checkout@v4 - with: - repository: langflow-ai/langflow - ref: load_flows_autologin_false - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -38,6 +35,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . + file: ./Dockerfile.langflow platforms: ${{ matrix.platform }} push: true tags: phact/langflow:responses-${{ matrix.arch }} diff --git a/README.md b/README.md index d79011a0..df1d6451 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ podman machine start ### Common Issues -See common issues and fixes: [docs/reference/troubleshooting.mdx](docs/docs/reference/troubleshooting.mdx) +See common issues and fixes: [docs/support/troubleshoot.mdx](docs/docs/reference/troubleshoot.mdx) diff --git a/docs/docs/reference/troubleshooting.mdx b/docs/docs/reference/troubleshooting.mdx deleted file mode 100644 index c1893ef5..00000000 --- a/docs/docs/reference/troubleshooting.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Troubleshooting -slug: /reference/troubleshooting ---- - -# Troubleshooting - -## Podman on macOS - -If using Podman on macOS, you may need to increase VM memory: - -```bash -podman machine stop -podman machine rm -podman machine init --memory 8192 # 8 GB example -podman machine start -``` - -## Common Issues - -1. OpenSearch fails to start: Check that `OPENSEARCH_PASSWORD` is set and meets requirements -2. Langflow connection issues: Verify `LANGFLOW_SUPERUSER` credentials are correct -3. Out of memory errors: Increase Docker memory allocation or use CPU-only mode -4. Port conflicts: Ensure ports 3000, 7860, 8000, 9200, 5601 are available diff --git a/docs/docs/support/troubleshoot.mdx b/docs/docs/support/troubleshoot.mdx new file mode 100644 index 00000000..57dcb4d3 --- /dev/null +++ b/docs/docs/support/troubleshoot.mdx @@ -0,0 +1,107 @@ +--- +title: Troubleshoot +slug: /support/troubleshoot +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This page provides troubleshooting advice for issues you might encounter when using OpenRAG or contributing to OpenRAG. + +## OpenSearch fails to start + +Check that `OPENSEARCH_PASSWORD` is set and meets requirements. +The password must contain at least 8 characters, and must contain at least one uppercase letter, one lowercase letter, one digit, and one special character that is strong. + +## Langflow connection issues + +Verify the `LANGFLOW_SUPERUSER` credentials are correct. + +## Memory errors + +### Container out of memory errors + +Increase Docker memory allocation or use [docker-compose-cpu.yml](https://github.com/langflow-ai/openrag/blob/main/docker-compose-cpu.yml) to deploy OpenRAG. + +### Podman on macOS memory issues + +If you're using Podman on macOS, you may need to increase VM memory on your Podman machine. +This example increases the machine size to 8 GB of RAM, which should be sufficient to run OpenRAG. + ```bash + podman machine stop + podman machine rm + podman machine init --memory 8192 # 8 GB example + podman machine start + ``` + +## Port conflicts + +Ensure ports 3000, 7860, 8000, 9200, 5601 are available. + +## Langflow container already exists + +If you are running other versions of Langflow containers on your machine, you may encounter an issue where Docker or Podman thinks Langflow is already up. + +Remove just the problem container, or clean up all containers and start fresh. + +To reset your local containers and pull new images, do the following: + +1. Stop your containers and completely remove them. + + + + + ```bash + # Stop all running containers + docker stop $(docker ps -q) + + # Remove all containers (including stopped ones) + docker rm --force $(docker ps -aq) + + # Remove all images + docker rmi --force $(docker images -q) + + # Remove all volumes + docker volume prune --force + + # Remove all networks (except default) + docker network prune --force + + # Clean up any leftover data + docker system prune --all --force --volumes + ``` + + + + + ```bash + # Stop all running containers + podman stop --all + + # Remove all containers (including stopped ones) + podman rm --all --force + + # Remove all images + podman rmi --all --force + + # Remove all volumes + podman volume prune --force + + # Remove all networks (except default) + podman network prune --force + + # Clean up any leftover data + podman system prune --all --force --volumes + ``` + + + + +2. Restart OpenRAG and upgrade to get the latest images for your containers. + ```bash + uv run openrag + ``` + +3. In the OpenRAG TUI, click **Status**, and then click **Upgrade**. +When the **Close** button is active, the upgrade is complete. +Close the window and open the OpenRAG appplication. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index c4175c09..25c51f6a 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -65,12 +65,13 @@ const config = { /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', + // image: 'img/docusaurus-social-card.jpg', navbar: { - title: 'OpenRAG', + // title: 'OpenRAG', logo: { alt: 'OpenRAG Logo', - src: 'img/logo.svg', + src: "img/logo-openrag-light.svg", + srcDark: "img/logo-openrag-dark.svg", href: '/', }, items: [ diff --git a/docs/sidebars.js b/docs/sidebars.js index 3048cb70..aa37e2b5 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -76,12 +76,12 @@ const sidebars = { }, { type: "category", - label: "Reference", + label: "Support", items: [ { type: "doc", - id: "reference/troubleshooting", - label: "Troubleshooting" + id: "support/troubleshoot", + label: "Troubleshoot" }, ], }, diff --git a/docs/static/img/logo-openrag-dark.svg b/docs/static/img/logo-openrag-dark.svg new file mode 100644 index 00000000..351243f5 --- /dev/null +++ b/docs/static/img/logo-openrag-dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/docs/static/img/logo-openrag-light.svg b/docs/static/img/logo-openrag-light.svg new file mode 100644 index 00000000..6a43c60d --- /dev/null +++ b/docs/static/img/logo-openrag-light.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/docs/static/img/logo.svg b/docs/static/img/logo.svg deleted file mode 100644 index 249f6888..00000000 --- a/docs/static/img/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/components/filter-icon-popover.tsx b/frontend/components/filter-icon-popover.tsx new file mode 100644 index 00000000..c0ce416b --- /dev/null +++ b/frontend/components/filter-icon-popover.tsx @@ -0,0 +1,169 @@ +"use client"; + +import React, { type SVGProps } from "react"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { + Book, + Scroll, + Library, + Map, + FileImage, + Layers3, + Database, + Folder, + Archive, + MessagesSquare, + SquareStack, + Ghost, + Gem, + Swords, + Bolt, + Shield, + Hammer, + Globe, + HardDrive, + Upload, + Cable, + ShoppingCart, + ShoppingBag, + Check, + Filter, +} from "lucide-react"; +import { filterAccentClasses } from "./knowledge-filter-panel"; +import { cn } from "@/lib/utils"; + +const ICON_MAP = { + filter: Filter, + book: Book, + scroll: Scroll, + library: Library, + map: Map, + image: FileImage, + layers3: Layers3, + database: Database, + folder: Folder, + archive: Archive, + messagesSquare: MessagesSquare, + squareStack: SquareStack, + ghost: Ghost, + gem: Gem, + swords: Swords, + bolt: Bolt, + shield: Shield, + hammer: Hammer, + globe: Globe, + hardDrive: HardDrive, + upload: Upload, + cable: Cable, + shoppingCart: ShoppingCart, + shoppingBag: ShoppingBag, +} as const; + +export type IconKey = keyof typeof ICON_MAP; + +export function iconKeyToComponent( + key?: string +): React.ComponentType> | undefined { + if (!key) return undefined; + return ( + ICON_MAP as Record>> + )[key]; +} + +const COLORS = [ + "zinc", + "pink", + "purple", + "indigo", + "emerald", + "amber", + "red", +] as const; +export type FilterColor = (typeof COLORS)[number]; + +const colorSwatchClasses = { + zinc: "bg-muted-foreground", + pink: "bg-accent-pink-foreground", + purple: "bg-accent-purple-foreground", + indigo: "bg-accent-indigo-foreground", + emerald: "bg-accent-emerald-foreground", + amber: "bg-accent-amber-foreground", + red: "bg-accent-red-foreground", +}; + +export interface FilterIconPopoverProps { + color: FilterColor; + iconKey: IconKey; + onColorChange: (c: FilterColor) => void; + onIconChange: (k: IconKey) => void; + triggerClassName?: string; +} + +export function FilterIconPopover({ + color, + iconKey, + onColorChange, + onIconChange, + triggerClassName, +}: FilterIconPopoverProps) { + const Icon = iconKeyToComponent(iconKey); + return ( + + + + + +
+
+ {COLORS.map((c) => ( + + ))} +
+
+ {Object.keys(ICON_MAP).map((k: string) => { + const OptIcon = ICON_MAP[k as IconKey]; + const active = iconKey === k; + return ( + + ); + })} +
+
+
+
+ ); +} diff --git a/frontend/components/knowledge-filter-list.tsx b/frontend/components/knowledge-filter-list.tsx index 2758d17f..bac0e5ca 100644 --- a/frontend/components/knowledge-filter-list.tsx +++ b/frontend/components/knowledge-filter-list.tsx @@ -2,24 +2,19 @@ import { useState } from "react"; import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; - -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { Filter, Loader2, Plus, Save, X } from "lucide-react"; +import { Loader2, Plus } from "lucide-react"; import { cn } from "@/lib/utils"; import { useGetFiltersSearchQuery, type KnowledgeFilter, } from "@/src/app/api/queries/useGetFiltersSearchQuery"; -import { useCreateFilter } from "@/src/app/api/mutations/useCreateFilter"; +import { useKnowledgeFilter } from "@/src/contexts/knowledge-filter-context"; import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; + FilterColor, + IconKey, + iconKeyToComponent, +} from "./filter-icon-popover"; +import { filterAccentClasses } from "./knowledge-filter-panel"; interface ParsedQueryData { query: string; @@ -30,6 +25,8 @@ interface ParsedQueryData { }; limit: number; scoreThreshold: number; + color: FilterColor; + icon: IconKey; } interface KnowledgeFilterListProps { @@ -42,10 +39,7 @@ export function KnowledgeFilterList({ onFilterSelect, }: KnowledgeFilterListProps) { const [searchQuery] = useState(""); - const [showCreateModal, setShowCreateModal] = useState(false); - const [createName, setCreateName] = useState(""); - const [createDescription, setCreateDescription] = useState(""); - const [creating, setCreating] = useState(false); + const { startCreateMode } = useKnowledgeFilter(); const { data, isFetching: loading } = useGetFiltersSearchQuery( searchQuery, @@ -54,57 +48,16 @@ export function KnowledgeFilterList({ const filters = data || []; - const createFilterMutation = useCreateFilter(); - const handleFilterSelect = (filter: KnowledgeFilter) => { + if (filter.id === selectedFilter?.id) { + onFilterSelect(null); + return; + } onFilterSelect(filter); }; const handleCreateNew = () => { - setShowCreateModal(true); - }; - - const handleCreateFilter = async () => { - if (!createName.trim()) return; - - setCreating(true); - try { - // Create a basic filter with wildcards (match everything by default) - const defaultFilterData = { - query: "", - filters: { - data_sources: ["*"], - document_types: ["*"], - owners: ["*"], - }, - limit: 10, - scoreThreshold: 0, - }; - - const result = await createFilterMutation.mutateAsync({ - name: createName.trim(), - description: createDescription.trim(), - queryData: JSON.stringify(defaultFilterData), - }); - - // Select the new filter from API response - onFilterSelect(result.filter); - - // Close modal and reset form - setShowCreateModal(false); - setCreateName(""); - setCreateDescription(""); - } catch (error) { - console.error("Error creating knowledge filter:", error); - } finally { - setCreating(false); - } - }; - - const handleCancelCreate = () => { - setShowCreateModal(false); - setCreateName(""); - setCreateDescription(""); + startCreateMode(); }; const parseQueryData = (queryData: string): ParsedQueryData => { @@ -113,7 +66,7 @@ export function KnowledgeFilterList({ return ( <> -
+
Knowledge Filters @@ -136,7 +89,7 @@ export function KnowledgeFilterList({
) : filters.length === 0 ? ( -
+
{searchQuery ? "No filters found" : "No saved filters"}
) : ( @@ -147,32 +100,45 @@ export function KnowledgeFilterList({ className={cn( "flex items-center gap-3 px-3 py-2 w-full rounded-lg hover:bg-accent hover:text-accent-foreground cursor-pointer group transition-colors", selectedFilter?.id === filter.id && - "bg-accent text-accent-foreground" + "active bg-accent text-accent-foreground" )} >
-
- -
+ {(() => { + const parsed = parseQueryData(filter.query_data) as ParsedQueryData; + const Icon = iconKeyToComponent(parsed.icon); + return ( +
+ {Icon && } +
+ ); + })()}
{filter.name}
{filter.description && ( -
+
{filter.description}
)}
-
+
{new Date(filter.created_at).toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric", })}
- + {(() => { const dataSources = parseQueryData(filter.query_data) .filters.data_sources; @@ -183,89 +149,11 @@ export function KnowledgeFilterList({
- {selectedFilter?.id === filter.id && ( - - )}
)) )}
- {/* Create Filter Dialog */} - - - - Create a new knowledge filter - - Save a reusable filter to quickly scope searches across your - knowledge base. - - -
-
- - setCreateName(e.target.value)} - className="mt-1" - /> -
-
- -