From 214d8bb281d674606773f89d84d8010d54619921 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 10 Mar 2025 17:23:59 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20feat:=20File=20Context=20(OCR)?= =?UTF-8?q?=20or=20Upload=20Files=20as=20Text=20(#262)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🌍 docs: Add OCR configuration documentation and object structure * 🌍 docs: Enhance OCR capabilities documentation and add new feature details * 🌍 docs: Add OCR configuration details and update links in documentation * 🌍 docs: Update OCR configuration details and enhance documentation for new features * 🌍 docs: Add OCR capability details and update changelog for new text extraction features * 🌍 docs: Clarify OCR processing details in agent context and update documentation for text extraction * 🌍 docs: Update OCR documentation title and enhance configuration details for Mistral model * fix: example OCR `mistralModel` and clarifying comment on configuration --- .../changelog/content/config_v1.2.2.mdx | 14 ++ pages/changelog/config_v1.2.2.mdx | 13 ++ .../object_structure/agents.mdx | 9 +- .../object_structure/config.mdx | 22 +++ .../librechat_yaml/object_structure/ocr.mdx | 98 +++++++++++++ pages/docs/features/agents.mdx | 24 +++- pages/docs/features/ocr.mdx | 134 ++++++++++++++++++ public/images/ocr/file_context_ocr.png | Bin 0 -> 10308 bytes public/images/ocr/upload_as_text.png | Bin 0 -> 15801 bytes 9 files changed, 307 insertions(+), 7 deletions(-) create mode 100644 components/changelog/content/config_v1.2.2.mdx create mode 100644 pages/changelog/config_v1.2.2.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/ocr.mdx create mode 100644 pages/docs/features/ocr.mdx create mode 100644 public/images/ocr/file_context_ocr.png create mode 100644 public/images/ocr/upload_as_text.png diff --git a/components/changelog/content/config_v1.2.2.mdx b/components/changelog/content/config_v1.2.2.mdx new file mode 100644 index 0000000..0668f67 --- /dev/null +++ b/components/changelog/content/config_v1.2.2.mdx @@ -0,0 +1,14 @@ +- Added [OCR Configuration](/docs/configuration/librechat_yaml/object_structure/ocr) + - Enables Optical Character Recognition (OCR) for extracting text from images and documents + - Supports two strategies: `mistral_ocr` (default) and `custom_ocr` (planned for future) + - Configurable parameters include `mistralModel`, `apiKey`, and `baseURL` + - Environment variable parsing supported for all parameters + - Available as an agent capability for processing images and documents + - Accessible via "Upload as Text" in chat and "File Context" in agent settings +- Added `ocr` to [Agent Capabilities](/docs/configuration/librechat_yaml/object_structure/agents#capabilities) + - New capability allows agents to extract text from images and documents + - Integrates with the OCR configuration for text extraction + - Adds "File Context (OCR)" as a new file upload category for agents + - This setting also affects the "Upload as Text" feature in chat (uploading as a message attachment) +- Added `titleModel` to [Shared Endpoint Settings](), making this configurable for all endpoints + - Note, this doesn't included `assistants` nor `all` configurations diff --git a/pages/changelog/config_v1.2.2.mdx b/pages/changelog/config_v1.2.2.mdx new file mode 100644 index 0000000..3f9cbd7 --- /dev/null +++ b/pages/changelog/config_v1.2.2.mdx @@ -0,0 +1,13 @@ +--- +date: 2025/3/10 +title: ⚙️ Config v1.2.2 +--- + +import { ChangelogHeader } from '@/components/changelog/ChangelogHeader' +import Content from '@/components/changelog/content/config_v1.2.2.mdx' + + + +--- + + diff --git a/pages/docs/configuration/librechat_yaml/object_structure/agents.mdx b/pages/docs/configuration/librechat_yaml/object_structure/agents.mdx index 0d60685..c32b124 100644 --- a/pages/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/pages/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -10,7 +10,7 @@ endpoints: recursionLimit: 50 disableBuilder: false # (optional) Agent Capabilities available to all users. Omit the ones you wish to exclude. Defaults to list below. - # capabilities: ["execute_code", "file_search", "actions", "tools"] + # capabilities: ["execute_code", "file_search", "actions", "tools", "ocr"] ``` > This configuration enables the builder interface for agents. @@ -52,7 +52,7 @@ disableBuilder: false ]} /> -**Default:** `["execute_code", "file_search", "actions", "tools"]` +**Default:** `["execute_code", "file_search", "actions", "tools", "ocr"]` **Example:** ```yaml filename="endpoints / agents / capabilities" @@ -61,6 +61,7 @@ capabilities: - "file_search" - "actions" - "tools" + - "ocr" ``` **Note:** This field is optional. If omitted, the default behavior is to include all the capabilities listed in the default. @@ -72,6 +73,7 @@ The `capabilities` field allows you to enable or disable specific functionalitie - **file_search**: Enables the agent to search and interact with files. - **actions**: Permits the agent to perform predefined actions. - **tools**: Grants the agent access to various tools. +- **ocr**: Enables uploading files as additional context, leveraging Optical Character Recognition for extracting text from images and documents. By specifying the capabilities, you can control the features available to users when interacting with agents. @@ -86,9 +88,10 @@ endpoints: capabilities: - "execute_code" - "actions" + - "ocr" ``` -In this example, the builder interface for agents is disabled, and only the `execute_code` and `actions` capabilities are enabled. +In this example, the builder interface for agents is disabled, and only the `execute_code`, `actions`, and `ocr` capabilities are enabled. ## Notes diff --git a/pages/docs/configuration/librechat_yaml/object_structure/config.mdx b/pages/docs/configuration/librechat_yaml/object_structure/config.mdx index 3ff30b1..b885b8c 100644 --- a/pages/docs/configuration/librechat_yaml/object_structure/config.mdx +++ b/pages/docs/configuration/librechat_yaml/object_structure/config.mdx @@ -78,6 +78,27 @@ ]} /> +## ocr + +**Key:** + + +**Subkeys:** + + +see: [OCR Config Object Structure](/docs/configuration/librechat_yaml/object_structure/ocr) + ## fileConfig **Key:** @@ -359,3 +380,4 @@ see: [MCP Servers Object Structure](/docs/configuration/librechat_yaml/object_st - [Azure OpenAI Endpoint Object Structure](/docs/configuration/librechat_yaml/object_structure/azure_openai) - [Assistants Endpoint Object Structure](/docs/configuration/librechat_yaml/object_structure/assistants_endpoint) - [Agents](/docs/configuration/librechat_yaml/object_structure/agents) +- [OCR Config Object Structure](/docs/configuration/librechat_yaml/object_structure/ocr) diff --git a/pages/docs/configuration/librechat_yaml/object_structure/ocr.mdx b/pages/docs/configuration/librechat_yaml/object_structure/ocr.mdx new file mode 100644 index 0000000..4c2466b --- /dev/null +++ b/pages/docs/configuration/librechat_yaml/object_structure/ocr.mdx @@ -0,0 +1,98 @@ +# OCR Config Object Structure + +## Overview + +The `ocr` object allows you to configure Optical Character Recognition (OCR) settings for the application, enabling the extraction of text from images. This section provides a detailed breakdown of the `ocr` object structure. + +There are 4 main fields under `ocr`: + + - `mistralModel` + - `apiKey` + - `baseURL` + - `strategy` + +**Notes:** + +- If using the Mistral OCR API, you don't need to edit your `librechat.yaml` file. + - You only need the following environment variables to get started: `OCR_API_KEY` and `OCR_BASEURL`. +- OCR functionality allows the application to extract text from images, which can then be processed by AI models. +- The default strategy is `mistral_ocr`, which uses Mistral's OCR capabilities. +- You can also configure a custom OCR service by setting the strategy to `custom_ocr`. +- If using the default Mistral OCR, you may optionally specify a specific Mistral model to use. +- Environment variable parsing is supported for `apiKey`, `baseURL`, and `mistralModel` parameters. +- A `user_provided` strategy option is planned for future releases but is not yet implemented. + +## Example + +```yaml filename="ocr" +ocr: + mistralModel: "mistral-ocr-latest" + apiKey: "your-mistral-api-key" + strategy: "mistral_ocr" +``` + +Example with custom OCR: + +```yaml filename="ocr with custom OCR" +ocr: + apiKey: "your-custom-ocr-api-key" + baseURL: "https://your-custom-ocr-service.com/api" + strategy: "custom_ocr" +``` + +## mistralModel + + + +```yaml filename="ocr / mistralModel" +ocr: + mistralModel: "mistral-ocr-latest" +``` + +## apiKey + + + +```yaml filename="ocr / apiKey" +ocr: + apiKey: "your-ocr-api-key" +``` + +## baseURL + + + +```yaml filename="ocr / baseURL" +ocr: + baseURL: "https://your-ocr-service.com/api" +``` + +## strategy + + + +```yaml filename="ocr / strategy" +ocr: + strategy: "custom_ocr" +``` + +**Available Strategies:** + +- `mistral_ocr`: Uses Mistral's OCR capabilities. +- `custom_ocr`: Uses a custom OCR service specified by the baseURL. diff --git a/pages/docs/features/agents.mdx b/pages/docs/features/agents.mdx index fa69600..a9b5587 100644 --- a/pages/docs/features/agents.mdx +++ b/pages/docs/features/agents.mdx @@ -58,6 +58,17 @@ The File Search capability enables: - Context-aware responses based on file contents - File attachment support at both agent and chat thread levels +### File Context (using Optical Character Recognition) + +The File Context (OCR) capability allows your agent to extract and process text from images and documents: + +- Extract text while maintaining document structure and formatting +- Process complex layouts including multi-column text and mixed content +- Handle tables, equations, and other specialized content +- Work with multilingual content +- [More info about OCR](/docs/features/ocr) + - **Currently uses Mistral OCR API which may incur costs** + ### Tools Agents can also be enhanced with various built-in tools: @@ -136,14 +147,19 @@ LibreChat is at the forefront of implementing flexible, scalable MCP server inte ## File Management -Agents support three distinct file upload categories: +Agents support four distinct file upload categories: 1. **Image Upload**: For visual content processing 2. **File Search Upload**: Documents for RAG capabilities 3. **Code Interpreter Upload**: Files for code processing +4. **File Context (OCR)**: Documents processed with OCR and added to the agent's instructions Files can be attached directly to the agent configuration or within individual chat threads. +![File Context using OCR for agents](/images/ocr/file_context_ocr.png) + +Files uploaded as "File Context" are processed using OCR to extract text, which is then added to the Agent's instructions. This is ideal for documents, images with text, or PDFs where you need the full text content of a file to be available to the agent. Note, the OCR is performed at the time of upload and is not stored as a separate file, rather purely as text in the database. + ## Sharing and Permissions ### Administrator Controls @@ -182,7 +198,7 @@ LibreChat allows admins to configure the use of agents via the [`librechat.yaml` - Provide clear, specific instructions for your agent - Carefully consider which tools are necessary for your use case -- Organize files appropriately across the three upload categories +- Organize files appropriately across the four upload categories - Review permission settings before sharing agents - Test your agent thoroughly before deploying to other users @@ -191,7 +207,7 @@ LibreChat allows admins to configure the use of agents via the [`librechat.yaml` 1. Select "Agents" from the endpoint dropdown menu 2. Open the Agent Builder panel 3. Fill out the required agent details -4. Configure desired capabilities (Code Interpreter, File Search) +4. Configure desired capabilities (Code Interpreter, File Search, File Context or OCR) 5. Add necessary tools and files 6. Set sharing permissions if desired 7. Create and start using your agent @@ -218,4 +234,4 @@ AI Agents in LibreChat provide a powerful way to create specialized assistants w --- -#LibreChat #AIAssistants #NoCode #OpenSource \ No newline at end of file +#LibreChat #AIAssistants #NoCode #OpenSource diff --git a/pages/docs/features/ocr.mdx b/pages/docs/features/ocr.mdx new file mode 100644 index 0000000..8c9a37c --- /dev/null +++ b/pages/docs/features/ocr.mdx @@ -0,0 +1,134 @@ +--- +title: File Context (OCR) +description: Learn how to use LibreChat's OCR capability to extract text from images and documents for AI processing. +--- + +# File Context via Optical Character Recognition (OCR) + +LibreChat's OCR (Optical Character Recognition) feature enables AI agents to extract and process text from images and documents. This capability enhances the AI's ability to work with visual content, making it possible to analyze, understand, and respond to information contained in images. + +## Overview + +OCR functionality in LibreChat allows agents to: + +- Extract text from images and documents +- Maintain document structure and formatting +- Process complex layouts including multi-column text +- Handle tables, equations, and other specialized content +- Work with multilingual content + +## Availability + +Currently, OCR is **only available as an agent capability**. This means you must use an agent via the Agents endpoint to leverage OCR functionality. + +## Configuration + +OCR can be enabled in the LibreChat configuration file (`librechat.yaml`). The OCR configuration supports two strategies: + +1. **Mistral OCR** (Default and currently the only available option) +2. **Custom OCR** (Planned for future releases) + +### Basic Configuration Example + +If using the Mistral OCR API, you only need the following environment variables to get started: + +```.env +# `.env` +OCR_API_KEY=your-mistral-api-key +# OCR_BASEURL=https://api.mistral.ai/v1 # this is the default value +``` + +For additional, detailed configuration options, see the [OCR Config Object Structure](/docs/configuration/librechat_yaml/object_structure/ocr). + +```yaml +# `librechat.yaml` +ocr: + mistralModel: "mistral-ocr-latest" # Optional: Specify Mistral model, defaults to "mistral-ocr-latest" + apiKey: "your-mistral-api-key" # Optional: Defaults to OCR_API_KEY env variable + baseURL: "https://api.mistral.ai/v1" # Optional: Defaults to OCR_BASEURL env variable, or Mistral's API if no variable set + strategy: "mistral_ocr" # Optional: Defaults to "mistral_ocr" (only option currently available) +``` + +## Mistral OCR + +Currently, LibreChat uses Mistral's OCR API as the default and only available OCR provider. Mistral OCR offers state-of-the-art document understanding capabilities. + +### Key Features of Mistral OCR + +- **Document Structure Preservation**: Maintains formatting like headers, paragraphs, lists, and tables +- **Multilingual Support**: Processes text in multiple languages and scripts +- **Complex Layout Handling**: Handles multi-column text and mixed content +- **Mathematical Expression Recognition**: Accurately processes equations and formulas +- **High-Speed Processing**: Processes up to 2000 pages per minute + +### Important Considerations + +- **Cost**: Using Mistral OCR may incur costs as it's a paid API service (though free trials may be available) +- **Data Privacy**: Data processed through Mistral OCR is subject to Mistral's cloud environment and their terms of service +- **Document Limitations**: + - Maximum file size: 50 MB + - Maximum document length: 1,000 pages + +### Future Plans + +- Mistral plans to make their OCR API available through their cloud partners, such as GCP and AWS, and enterprise self-hosting for organizations with stringent data privacy requirements ([source](https://mistral.ai/fr/news/mistral-ocr)). +- LibreChat will continue to support Mistral OCR and explore additional OCR providers, including open-source solutions, for enhanced functionality. +- LibreChat currently does not include the parsed image content from the OCR process in its responses, even though services like [Mistral's OCR API may provide](https://docs.mistral.ai/api/#tag/ocr) these in the result. This feature may be supported in future updates. + +## Using File Context (OCR) in LibreChat + +LibreChat provides two main ways to use OCR functionality: + +### 1. Upload as Text in Chat + +In any chat conversation, you can use OCR to extract text from images or documents: + +1. Click the attachment icon in the chat input +2. Select "Upload as Text" from the menu +3. Choose an image or document file +4. The OCR system will process the file and insert the extracted text into your message + +![Upload as Text option in the attachment menu](/images/ocr/upload_as_text.png) + +### 2. File Context for Agents + +When working with agents, you can add documents as context using OCR: + +1. Open the Agent Builder panel or edit an existing agent +2. In the File Context section, click "Upload File Context" +3. Select a document or image file +4. The OCR system will extract text from the file and add it to the agent's instructions + +![File Context using OCR for agents](/images/ocr/file_context_ocr.png) + +Files uploaded as "Context" are processed using OCR to extract text, which is then added to the Agent's instructions. This is ideal for documents, images with text, or PDFs where you need the full text content of a file to be available to the agent. + +**Note,** the OCR is performed at the time of upload and is not stored as a separate file, rather purely as text in the database. + +## Example Use Cases + +- **Document Analysis**: Extract and analyze text from scanned documents, PDFs, or images +- **Data Extraction**: Pull specific information from forms, receipts, or invoices +- **Research Assistance**: Process academic papers, articles, or books +- **Language Translation**: Extract text from foreign language documents for translation +- **Content Digitization**: Convert printed materials into digital, searchable text + +## Limitations + +- OCR accuracy may vary depending on image quality, document complexity, and text clarity +- Some specialized formatting or unusual layouts might not be perfectly preserved +- Very large documents may be truncated due to token limitations of the underlying AI models + +## Future Enhancements + +LibreChat plans to expand OCR capabilities in future releases: + +- Support for custom OCR providers +- A `user_provided` strategy option that will allow users to choose their preferred OCR service +- Integration with open-source OCR solutions +- Enhanced document processing options +- More granular control over OCR settings + +--- + +For more information on configuring OCR, see the [OCR Config Object Structure](/docs/configuration/librechat_yaml/object_structure/ocr). diff --git a/public/images/ocr/file_context_ocr.png b/public/images/ocr/file_context_ocr.png new file mode 100644 index 0000000000000000000000000000000000000000..1608b433f25b71476f930c442c065f918f542860 GIT binary patch literal 10308 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 CT6_Hf literal 0 HcmV?d00001 diff --git a/public/images/ocr/upload_as_text.png b/public/images/ocr/upload_as_text.png new file mode 100644 index 0000000000000000000000000000000000000000..58b934bd3e9334325f995e31bc4a9477efb09f3d GIT binary patch literal 15801 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