diff --git a/CLAUDE.md b/CLAUDE.md index 58d1217afe..f42613a669 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,14 +5,16 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview RAGFlow is an open-source RAG (Retrieval-Augmented Generation) engine based on deep document understanding. It's a full-stack application with: + - Python backend (Flask-based API server) -- React/TypeScript frontend (built with UmiJS) +- React/TypeScript frontend (built with vitejs) - Microservices architecture with Docker deployment - Multiple data stores (MySQL, Elasticsearch/Infinity, Redis, MinIO) ## Architecture ### Backend (`/api/`) + - **Main Server**: `api/ragflow_server.py` - Flask application entry point - **Apps**: Modular Flask blueprints in `api/apps/` for different functionalities: - `kb_app.py` - Knowledge base management @@ -24,25 +26,29 @@ RAGFlow is an open-source RAG (Retrieval-Augmented Generation) engine based on d - **Models**: Database models in `api/db/db_models.py` ### Core Processing (`/rag/`) + - **Document Processing**: `deepdoc/` - PDF parsing, OCR, layout analysis - **LLM Integration**: `rag/llm/` - Model abstractions for chat, embedding, reranking - **RAG Pipeline**: `rag/flow/` - Chunking, parsing, tokenization - **Graph RAG**: `rag/graphrag/` - Knowledge graph construction and querying ### Agent System (`/agent/`) + - **Components**: Modular workflow components (LLM, retrieval, categorize, etc.) - **Templates**: Pre-built agent workflows in `agent/templates/` - **Tools**: External API integrations (Tavily, Wikipedia, SQL execution, etc.) ### Frontend (`/web/`) -- React/TypeScript with UmiJS framework -- Ant Design + shadcn/ui components + +- React/TypeScript with vitejs framework +- shadcn/ui components - State management with Zustand - Tailwind CSS for styling ## Common Development Commands ### Backend Development + ```bash # Install Python dependencies uv sync --python 3.12 --all-extras @@ -66,6 +72,7 @@ ruff format ``` ### Frontend Development + ```bash cd web npm install @@ -76,6 +83,7 @@ npm run test # Jest tests ``` ### Docker Development + ```bash # Full stack with Docker cd docker @@ -104,6 +112,7 @@ docker build --platform linux/amd64 -f Dockerfile -t infiniflow/ragflow:nightly ## Database Engines RAGFlow supports switching between Elasticsearch (default) and Infinity: + - Set `DOC_ENGINE=infinity` in `docker/.env` to use Infinity - Requires container restart: `docker compose down -v && docker compose up -d` @@ -114,3 +123,12 @@ RAGFlow supports switching between Elasticsearch (default) and Infinity: - Docker & Docker Compose - uv package manager - 16GB+ RAM, 50GB+ disk space + +1. Think before acting. Read existing files before writing code. +2. Be concise in output but thorough in reasoning. +3. Prefer editing over rewriting whole files. +4. Do not re-read files you have already read. +5. Test your code before declaring done. +6. No sycophantic openers or closing fluff. +7. Keep solutions simple and direct. +8. User instructions always override this file. diff --git a/web/src/components/metadata-filter/metadata-filter-conditions.tsx b/web/src/components/metadata-filter/metadata-filter-conditions.tsx index 1fb6b4cdf4..7b4fb07277 100644 --- a/web/src/components/metadata-filter/metadata-filter-conditions.tsx +++ b/web/src/components/metadata-filter/metadata-filter-conditions.tsx @@ -28,6 +28,140 @@ import { Card, CardContent } from '../ui/card'; import { InputSelect } from '../ui/input-select'; import { RAGFlowSelect } from '../ui/select'; +type ConditionCardsProps = { + fieldName: string; + index: number; + name: string; + remove: (index: number) => void; + switchOperatorOptions: ReturnType; + metadata: ReturnType; + canReference?: boolean; +}; + +function ConditionCards({ + fieldName, + index, + name, + remove, + switchOperatorOptions, + metadata, + canReference, +}: ConditionCardsProps) { + const { t } = useTranslation(); + const form = useFormContext(); + const op = useWatch({ name: `${name}.${index}.op` }); + const key = useWatch({ name: fieldName }); + const valueOptions = useMemo(() => { + if (!key || !metadata?.data || !metadata?.data[key]) return []; + if (typeof metadata?.data[key] === 'object') { + return Object.keys(metadata?.data[key]).map((item: string) => ({ + value: item, + label: item, + })); + } + return []; + }, [key, metadata?.data]); + + const handleChangeOp = useCallback( + (value: string) => { + form.setValue(`${name}.${index}.op`, value); + if (!['in', 'not in'].includes(value) && !['in', 'not in'].includes(op)) { + return; + } + if (value === 'in' || value === 'not in') { + form.setValue(`${name}.${index}.value`, []); + } else { + form.setValue(`${name}.${index}.value`, ''); + } + }, + [form, index, op, name], + ); + + return ( +
+ +
+ ( + + + + + + + )} + /> +
+ + ( + + + { + handleChangeOp(value); + }} + options={switchOperatorOptions} + onlyShowSelectedIcon + triggerClassName="w-30 bg-transparent border-none" + /> + + + + )} + /> +
+
+ + { + return ( + + + {canReference ? ( + + ) : ( + + )} + + + + ); + }} + /> + +
+ +
+ ); +} + export function MetadataFilterConditions({ kbIds, prefix = '', @@ -64,129 +198,6 @@ export function MetadataFilterConditions({ [append, fields.length, form, logic], ); - function ConditionCards({ - fieldName, - index, - }: { - fieldName: string; - index: number; - }) { - const { t } = useTranslation(); - const form = useFormContext(); - const op = useWatch({ name: `${name}.${index}.op` }); - const key = useWatch({ name: fieldName }); - const valueOptions = useMemo(() => { - if (!key || !metadata?.data || !metadata?.data[key]) return []; - if (typeof metadata?.data[key] === 'object') { - return Object.keys(metadata?.data[key]).map((item: string) => ({ - value: item, - label: item, - })); - } - return []; - }, [key]); - - const handleChangeOp = useCallback( - (value: string) => { - form.setValue(`${name}.${index}.op`, value); - if ( - !['in', 'not in'].includes(value) && - !['in', 'not in'].includes(op) - ) { - return; - } - if (value === 'in' || value === 'not in') { - form.setValue(`${name}.${index}.value`, []); - } else { - form.setValue(`${name}.${index}.value`, ''); - } - }, - [form, index, op], - ); - return ( -
- -
- ( - - - - - - - )} - /> -
- - ( - - - { - handleChangeOp(value); - }} - options={switchOperatorOptions} - onlyShowSelectedIcon - triggerClassName="w-30 bg-transparent border-none" - /> - - - - )} - /> -
-
- - { - return ( - - - {canReference ? ( - - ) : ( - - )} - - - - ); - }} - /> - -
- -
- ); - } return (
@@ -218,6 +229,11 @@ export function MetadataFilterConditions({ key={field.id} fieldName={typeField} index={index} + name={name} + remove={remove} + switchOperatorOptions={switchOperatorOptions} + metadata={metadata} + canReference={canReference} /> ); })}