From 3b23b96a27ee5c5e6a308b0eb7926be408a90487 Mon Sep 17 00:00:00 2001 From: joaoback <156559121+joaoback@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:11:22 -0300 Subject: [PATCH 01/29] Update translation.json (pt-BR) New translations of the items added in the latest version. --- src/lib/i18n/locales/pt-BR/translation.json | 34 ++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index ca11c2c57f..5f3d9bce0a 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -95,7 +95,7 @@ "Allow Continue Response": "Permitir Resposta Contínua", "Allow Delete Messages": "Permitir Exclusão de Mensagens", "Allow File Upload": "Permitir Envio de arquivos", - "Allow Group Sharing": "", + "Allow Group Sharing": "Permitir compartilhamento em grupo", "Allow Multiple Models in Chat": "Permitir Vários Modelos no Chat", "Allow non-local voices": "Permitir vozes não locais", "Allow Rate Response": "Permitir Avaliar Resposta", @@ -145,7 +145,7 @@ "Archived Chats": "Chats Arquivados", "archived-chat-export": "exportação de chats arquivados", "Are you sure you want to clear all memories? This action cannot be undone.": "Tem certeza de que deseja apagar todas as memórias? Esta ação não pode ser desfeita.", - "Are you sure you want to delete \"{{NAME}}\"?": "", + "Are you sure you want to delete \"{{NAME}}\"?": "Tem certeza de que deseja excluir \"{{NAME}}\"?", "Are you sure you want to delete this channel?": "Tem certeza de que deseja excluir este canal?", "Are you sure you want to delete this message?": "Tem certeza de que deseja excluir esta mensagem?", "Are you sure you want to unarchive all archived chats?": "Você tem certeza que deseja desarquivar todos os chats arquivados?", @@ -390,14 +390,14 @@ "Default description enabled": "Descrição padrão habilitada", "Default Features": "Recursos padrão", "Default Filters": "Filtros padrão", - "Default Group": "", + "Default Group": "Grupo padrão", "Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model's built-in tool-calling capabilities, but requires the model to inherently support this feature.": "O modo padrão funciona com uma gama mais ampla de modelos, chamando as ferramentas uma vez antes da execução. O modo nativo aproveita os recursos integrados de chamada de ferramentas do modelo, mas exige que o modelo suporte esse recurso inerentemente.", "Default Model": "Modelo Padrão", "Default model updated": "Modelo padrão atualizado", "Default Models": "Modelos Padrão", "Default permissions": "Permissões padrão", "Default permissions updated successfully": "Permissões padrão atualizadas com sucesso", - "Default Pinned Models": "", + "Default Pinned Models": "Modelos fixados padrão", "Default Prompt Suggestions": "Sugestões de Prompt Padrão", "Default to 389 or 636 if TLS is enabled": "O padrão é 389 ou 636 se o TLS estiver habilitado", "Default to ALL": "Padrão para TODOS", @@ -406,7 +406,7 @@ "Delete": "Excluir", "Delete a model": "Excluir um modelo", "Delete All Chats": "Excluir Todos os Chats", - "Delete all contents inside this folder": "", + "Delete all contents inside this folder": "Apague todo o conteúdo desta pasta.", "Delete All Models": "Excluir Todos os Modelos", "Delete Chat": "Excluir Chat", "Delete chat?": "Excluir chat?", @@ -735,7 +735,7 @@ "Features": "Funcionalidades", "Features Permissions": "Permissões das Funcionalidades", "February": "Fevereiro", - "Feedback deleted successfully": "", + "Feedback deleted successfully": "O feedback foi excluído com sucesso.", "Feedback Details": "Detalhes do comentário", "Feedback History": "Histórico de comentários", "Feedbacks": "Comentários", @@ -750,7 +750,7 @@ "File size should not exceed {{maxSize}} MB.": "Arquivo não pode exceder {{maxSize}} MB.", "File Upload": "Upload de arquivo", "File uploaded successfully": "Arquivo carregado com sucesso", - "File uploaded!": "", + "File uploaded!": "Arquivo enviado!", "Files": "Arquivos", "Filter": "Filtro", "Filter is now globally disabled": "O filtro está agora desativado globalmente", @@ -864,7 +864,7 @@ "Image Compression": "Compressão de imagem", "Image Compression Height": "Altura de compressão da imagem", "Image Compression Width": "Largura de compressão de imagem", - "Image Edit": "", + "Image Edit": "Edição de imagem", "Image Edit Engine": "Motor de edição de imagens", "Image Generation": "Geração de Imagem", "Image Generation Engine": "Motor de Geração de Imagem", @@ -949,7 +949,7 @@ "Knowledge Name": "Nome da Base de Conhecimento", "Knowledge Public Sharing": "Compartilhamento Público da Base de Conhecimento", "Knowledge reset successfully.": "Conhecimento resetado com sucesso.", - "Knowledge Sharing": "", + "Knowledge Sharing": Compartilhamento da Base de Conhecimento "Knowledge updated successfully": "Conhecimento atualizado com sucesso", "Kokoro.js (Browser)": "", "Kokoro.js Dtype": "", @@ -1071,8 +1071,8 @@ "Models Access": "Acesso aos Modelos", "Models configuration saved successfully": "Configuração de modelos salva com sucesso", "Models imported successfully": "", - "Models Public Sharing": "Modelos de Compartilhamento Público", - "Models Sharing": "", + "Models Public Sharing": "Compartilhamento Público de Modelos", + "Models Sharing": "Compartilhamento de Modelos", "Mojeek Search API Key": "Chave de API Mojeel Search", "More": "Mais", "More Concise": "Mais conciso", @@ -1139,7 +1139,7 @@ "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Nota: Se você definir uma pontuação mínima, a pesquisa retornará apenas documentos com pontuação igual ou superior à pontuação mínima.", "Notes": "Notas", "Notes Public Sharing": "Compartilhamento Público das Notas", - "Notes Sharing": "", + "Notes Sharing": "Compartilhamento de notas", "Notification Sound": "Som de notificação", "Notification Webhook": "Webhook de notificação", "Notifications": "Notificações", @@ -1285,7 +1285,7 @@ "Prompts": "Prompts", "Prompts Access": "Acessar prompts", "Prompts Public Sharing": "Compartilhamento Público dos Prompts", - "Prompts Sharing": "", + "Prompts Sharing": "Compatilhamento de Prompts", "Provider Type": "Tipo de provedor", "Public": "Público", "Pull \"{{searchValue}}\" from Ollama.com": "Obter \"{{searchValue}}\" de Ollama.com", @@ -1470,7 +1470,7 @@ "Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.": "Define a semente numérica aleatória a ser usada para geração. Definir um número específico fará com que o modelo gere o mesmo texto para o mesmo prompt.", "Sets the size of the context window used to generate the next token.": "Define o tamanho da janela de contexto usada para gerar o próximo token.", "Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying multiple separate stop parameters in a modelfile.": "Define as sequências de parada a serem usadas. Quando esse padrão for encontrado, o modelo de linguagem (LLM) parará de gerar texto e retornará. Vários padrões de parada podem ser definidos especificando parâmetros de parada separados em um arquivo de modelo.", - "Setting": "", + "Setting": "Configuração", "Settings": "Configurações", "Settings saved successfully!": "Configurações salvas com sucesso!", "Share": "Compartilhar", @@ -1650,8 +1650,8 @@ "Tools are a function calling system with arbitrary code execution": "Ferramentas são um sistema de chamada de funções com execução de código arbitrário", "Tools Function Calling Prompt": "Prompt de chamada de função de ferramentas", "Tools have a function calling system that allows arbitrary code execution.": "Ferramentas possuem um sistema de chamada de funções que permite a execução de código arbitrário.", - "Tools Public Sharing": "Ferramentas Compartilhamento Público", - "Tools Sharing": "", + "Tools Public Sharing": "Compartilhamento Público de Ferramentas", + "Tools Sharing": "Compartilhamento de Ferramentas", "Top K": "Top K", "Top K Reranker": "", "Transformers": "", @@ -1699,7 +1699,7 @@ "Upload Pipeline": "Fazer upload de Pipeline", "Upload Progress": "Progresso do Upload", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Progresso do upload: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", - "Uploading file...": "", + "Uploading file...": "Enviando arquivo...", "URL": "", "URL is required": "URL é obrigratória", "URL Mode": "Modo URL", From a7b611c0e5202a08e63a2ed4d44de4bf86fe3e11 Mon Sep 17 00:00:00 2001 From: Alexandr Promakh Date: Mon, 24 Nov 2025 19:51:52 +0000 Subject: [PATCH 02/29] fix: "No connection adapters were found" routers/images.py (#19435) --- backend/open_webui/routers/images.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/open_webui/routers/images.py b/backend/open_webui/routers/images.py index 4cc2a99101..8aabf0f73b 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -549,9 +549,7 @@ async def image_generations( if ENABLE_FORWARD_USER_INFO_HEADERS: headers = include_user_info_headers(headers, user) - url = ( - f"{request.app.state.config.IMAGES_OPENAI_API_BASE_URL}/images/generations", - ) + url = f"{request.app.state.config.IMAGES_OPENAI_API_BASE_URL}/images/generations" if request.app.state.config.IMAGES_OPENAI_API_VERSION: url = f"{url}?api-version={request.app.state.config.IMAGES_OPENAI_API_VERSION}" From 0a687980eef8cba775d05faed632007c059dc269 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 24 Nov 2025 21:22:23 +0100 Subject: [PATCH 03/29] Update knowledge.py (#19434) --- backend/open_webui/routers/knowledge.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index 71722d706e..ad47fc1686 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -1,6 +1,7 @@ from typing import List, Optional from pydantic import BaseModel from fastapi import APIRouter, Depends, HTTPException, status, Request, Query +from fastapi.concurrency import run_in_threadpool import logging from open_webui.models.knowledge import ( @@ -223,7 +224,8 @@ async def reindex_knowledge_files(request: Request, user=Depends(get_verified_us failed_files = [] for file in files: try: - process_file( + await run_in_threadpool( + process_file, request, ProcessFileForm( file_id=file.id, collection_name=knowledge_base.id From f0d75e3a480452b64349e12395df7a629f78064b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 24 Nov 2025 15:39:13 -0500 Subject: [PATCH 04/29] refac/fix: db operations --- backend/open_webui/models/models.py | 11 ++++++++--- backend/open_webui/models/users.py | 11 ++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index f9390b405d..e902a978d1 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -290,10 +290,15 @@ class ModelsTable: models = [] for model, user in items: - model_model = ModelModel.model_validate(model) - user_model = UserResponse(**UserModel.model_validate(user).model_dump()) models.append( - ModelUserResponse(**model_model.model_dump(), user=user_model) + ModelUserResponse( + **ModelModel.model_validate(model).model_dump(), + user=( + UserResponse(**UserModel.model_validate(user).model_dump()) + if user + else None + ), + ) ) return ModelListResponse(items=models, total=total) diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index 256d3bc75e..445eb51128 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -227,9 +227,7 @@ class UsersTable: ) -> dict: with get_db() as db: # Join GroupMember so we can order by group_id when requested - query = db.query(User).outerjoin( - GroupMember, GroupMember.user_id == User.id - ) + query = db.query(User) if filter: query_key = filter.get("query") @@ -245,6 +243,7 @@ class UsersTable: direction = filter.get("direction") if order_by and order_by.startswith("group_id:"): + query = query.outerjoin(GroupMember, GroupMember.user_id == User.id) group_id = order_by.split(":", 1)[1] if direction == "asc": @@ -291,11 +290,13 @@ class UsersTable: query = query.order_by(User.created_at.desc()) # Count BEFORE pagination + query = query.distinct(User.id) total = query.count() - if skip: + # correct pagination logic + if skip is not None: query = query.offset(skip) - if limit: + if limit is not None: query = query.limit(limit) users = query.all() From b875a438f03dcb87a1a4d83289396ec1447f9e9e Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 24 Nov 2025 21:39:53 +0100 Subject: [PATCH 05/29] Update translation.json (#19445) Co-authored-by: Tim Baek --- src/lib/i18n/locales/de-DE/translation.json | 32 ++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 9cb64887d3..dc735db98e 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -95,7 +95,7 @@ "Allow Continue Response": "Erlaube fortgesetzte Antwort", "Allow Delete Messages": "Löschen von Nachrichten erlauben", "Allow File Upload": "Hochladen von Dateien erlauben", - "Allow Group Sharing": "", + "Allow Group Sharing": "In diese Gruppe teilen erlauben", "Allow Multiple Models in Chat": "Multiple Modelle in Chat erlauben", "Allow non-local voices": "Nicht-lokale Stimmen erlauben", "Allow Rate Response": "Erlaube Bewertung der Antwort", @@ -145,7 +145,7 @@ "Archived Chats": "Archivierte Chats", "archived-chat-export": "archivierter-chat-export", "Are you sure you want to clear all memories? This action cannot be undone.": "Sind Sie sicher, dass Sie alle Erinnerungen löschen möchten? Diese Handlung kann nicht rückgängig gemacht werden.", - "Are you sure you want to delete \"{{NAME}}\"?": "", + "Are you sure you want to delete \"{{NAME}}\"?": "Bist du dir sicher, dass du \"{{NAME}}\" löschen willst?", "Are you sure you want to delete this channel?": "Sind Sie sicher, dass Sie diesen Kanal löschen möchten?", "Are you sure you want to delete this message?": "Sind Sie sicher, dass Sie diese Nachricht löschen möchten?", "Are you sure you want to unarchive all archived chats?": "Sind Sie sicher, dass Sie alle archivierten Chats wiederherstellen möchten?", @@ -390,14 +390,14 @@ "Default description enabled": "Standard Beschreibung aktiviert", "Default Features": "Standardfunktionen", "Default Filters": "Standardfilter", - "Default Group": "", + "Default Group": "Standard Gruppe", "Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model's built-in tool-calling capabilities, but requires the model to inherently support this feature.": "Der Standardmodus funktioniert mit einer breiteren Auswahl von Modellen, indem er Werkzeuge einmal vor der Ausführung aufruft. Der native Modus nutzt die integrierten Tool-Aufrufmöglichkeiten des Modells, erfordert jedoch, dass das Modell diese Funktion von Natur aus unterstützt.", "Default Model": "Standardmodell", "Default model updated": "Standardmodell aktualisiert", "Default Models": "Standardmodelle", "Default permissions": "Standardberechtigungen", "Default permissions updated successfully": "Standardberechtigungen erfolgreich aktualisiert", - "Default Pinned Models": "", + "Default Pinned Models": "Standard angepinnte Modelle", "Default Prompt Suggestions": "Prompt-Vorschläge", "Default to 389 or 636 if TLS is enabled": "Standardmäßig auf 389 oder 636 setzen, wenn TLS aktiviert ist", "Default to ALL": "Standardmäßig auf ALLE setzen", @@ -406,7 +406,7 @@ "Delete": "Löschen", "Delete a model": "Ein Modell löschen", "Delete All Chats": "Alle Chats löschen", - "Delete all contents inside this folder": "", + "Delete all contents inside this folder": "Lösche ganzen Ordnerinhalt", "Delete All Models": "Alle Modelle löschen", "Delete Chat": "Chat löschen", "Delete chat?": "Chat löschen?", @@ -735,7 +735,7 @@ "Features": "Funktionalitäten", "Features Permissions": "Funktionen-Berechtigungen", "February": "Februar", - "Feedback deleted successfully": "", + "Feedback deleted successfully": "Feedback erfolgreich gelöscht", "Feedback Details": "Feedback-Details", "Feedback History": "Feedback-Verlauf", "Feedbacks": "Feedbacks", @@ -750,7 +750,7 @@ "File size should not exceed {{maxSize}} MB.": "Datei darf nicht größer als {{maxSize}} MB sein.", "File Upload": "Dateiupload", "File uploaded successfully": "Datei erfolgreich hochgeladen", - "File uploaded!": "", + "File uploaded!": "Datei hochgeladen!", "Files": "Dateien", "Filter": "Filter", "Filter is now globally disabled": "Filter ist jetzt global deaktiviert", @@ -864,7 +864,7 @@ "Image Compression": "Bildkomprimierung", "Image Compression Height": "Bildkompression Länge", "Image Compression Width": "Bildkompression Breite", - "Image Edit": "", + "Image Edit": "Bildbearbeitung", "Image Edit Engine": "Bildbearbeitungsengine", "Image Generation": "Bildgenerierung", "Image Generation Engine": "Bildgenerierungs-Engine", @@ -949,7 +949,7 @@ "Knowledge Name": "Wissensname", "Knowledge Public Sharing": "Öffentliche Freigabe von Wissen", "Knowledge reset successfully.": "Wissen erfolgreich zurückgesetzt.", - "Knowledge Sharing": "", + "Knowledge Sharing": "Wissensspeicher teilen", "Knowledge updated successfully": "Wissen erfolgreich aktualisiert", "Kokoro.js (Browser)": "Kokoro.js (Browser)", "Kokoro.js Dtype": "Kokoro.js Dtype", @@ -1015,7 +1015,7 @@ "Max Upload Size": "Maximale Uploadgröße", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es können maximal 3 Modelle gleichzeitig heruntergeladen werden. Bitte versuchen Sie es später erneut.", "May": "Mai", - "MBR": "", + "MBR": "MBR", "MCP": "MCP", "MCP support is experimental and its specification changes often, which can lead to incompatibilities. OpenAPI specification support is directly maintained by the Open WebUI team, making it the more reliable option for compatibility.": "Die MCP-Unterstützung ist experimentell und ihre Spezifikation ändert sich häufig, was zu Inkompatibilitäten führen kann. Die Unterstützung der OpenAPI-Spezifikation wird direkt vom Open‑WebUI‑Team gepflegt und ist daher die verlässlichere Option in Bezug auf Kompatibilität.", "Medium": "Mittel", @@ -1072,7 +1072,7 @@ "Models configuration saved successfully": "Modellkonfiguration erfolgreich gespeichert", "Models imported successfully": "Modelle erfolgreich importiert", "Models Public Sharing": "Öffentliche Freigabe von Modellen", - "Models Sharing": "", + "Models Sharing": "Modelle teilen", "Mojeek Search API Key": "Mojeek Search API-Schlüssel", "More": "Mehr", "More Concise": "Kürzer", @@ -1139,7 +1139,7 @@ "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Hinweis: Wenn Sie eine Mindestpunktzahl festlegen, werden in der Suche nur Dokumente mit einer Punktzahl größer oder gleich der Mindestpunktzahl zurückgegeben.", "Notes": "Notizen", "Notes Public Sharing": "Öffentliche Freigabe von Notizen", - "Notes Sharing": "", + "Notes Sharing": "Notizen teilen", "Notification Sound": "Benachrichtigungston", "Notification Webhook": "Benachrichtigungs-Webhook", "Notifications": "Benachrichtigungen", @@ -1285,7 +1285,7 @@ "Prompts": "Prompts", "Prompts Access": "Prompt-Zugriff", "Prompts Public Sharing": "Öffentliche Freigabe von Prompts", - "Prompts Sharing": "", + "Prompts Sharing": "Prompts teilen", "Provider Type": "Anbietertyp", "Public": "Öffentlich", "Pull \"{{searchValue}}\" from Ollama.com": "\"{{searchValue}}\" von Ollama.com beziehen", @@ -1469,7 +1469,7 @@ "Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.": "Legt den Startwert für die Zufallszahlengenerierung fest. Wenn dieser auf eine bestimmte Zahl gesetzt wird, erzeugt das Modell für denselben Prompt immer denselben Text.", "Sets the size of the context window used to generate the next token.": "Legt die Größe des Kontextfensters fest, das zur Generierung des nächsten Token verwendet wird.", "Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying multiple separate stop parameters in a modelfile.": "Legt die zu verwendenden Stoppsequenzen fest. Wenn dieses Muster erkannt wird, stoppt das LLM die Textgenerierung und gibt zurück. Mehrere Stoppmuster können festgelegt werden, indem mehrere separate Stopp-Parameter in einer Modelldatei angegeben werden.", - "Setting": "", + "Setting": "Einstellung", "Settings": "Einstellungen", "Settings saved successfully!": "Einstellungen erfolgreich gespeichert!", "Share": "Teilen", @@ -1650,7 +1650,7 @@ "Tools Function Calling Prompt": "Prompt für Funktionssystemaufrufe", "Tools have a function calling system that allows arbitrary code execution.": "Werkzeuge verfügen über ein Funktionssystem, das die Ausführung beliebigen Codes ermöglicht.", "Tools Public Sharing": "Öffentliche Freigabe von Werkzeugen", - "Tools Sharing": "", + "Tools Sharing": "Werkzeuge teilen", "Top K": "Top-K", "Top K Reranker": "Top-K Reranker", "Transformers": "Transformers", @@ -1698,7 +1698,7 @@ "Upload Pipeline": "Pipeline hochladen", "Upload Progress": "Fortschritt", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Fortschritt: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", - "Uploading file...": "", + "Uploading file...": "Datei hochladen...", "URL": "URL", "URL is required": "URL wird benötigt", "URL Mode": "URL-Modus", From 9c19d0abd47d1451cf0b96a3547d3d5a429c8c92 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 24 Nov 2025 16:01:13 -0500 Subject: [PATCH 06/29] refac/breaking: docling params --- backend/open_webui/config.py | 88 +------- backend/open_webui/main.py | 24 +-- backend/open_webui/retrieval/loaders/main.py | 72 ++----- backend/open_webui/routers/retrieval.py | 114 +--------- .../admin/Settings/Documents.svelte | 203 +----------------- 5 files changed, 40 insertions(+), 461 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index d0e693e319..79965596a2 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -2538,6 +2538,12 @@ DOCLING_SERVER_URL = PersistentConfig( os.getenv("DOCLING_SERVER_URL", "http://docling:5001"), ) +DOCLING_API_KEY = PersistentConfig( + "DOCLING_API_KEY", + "rag.docling_api_key", + os.getenv("DOCLING_API_KEY", ""), +) + docling_params = os.getenv("DOCLING_PARAMS", "") try: docling_params = json.loads(docling_params) @@ -2550,88 +2556,6 @@ DOCLING_PARAMS = PersistentConfig( docling_params, ) -DOCLING_DO_OCR = PersistentConfig( - "DOCLING_DO_OCR", - "rag.docling_do_ocr", - os.getenv("DOCLING_DO_OCR", "True").lower() == "true", -) - -DOCLING_FORCE_OCR = PersistentConfig( - "DOCLING_FORCE_OCR", - "rag.docling_force_ocr", - os.getenv("DOCLING_FORCE_OCR", "False").lower() == "true", -) - -DOCLING_OCR_ENGINE = PersistentConfig( - "DOCLING_OCR_ENGINE", - "rag.docling_ocr_engine", - os.getenv("DOCLING_OCR_ENGINE", "tesseract"), -) - -DOCLING_OCR_LANG = PersistentConfig( - "DOCLING_OCR_LANG", - "rag.docling_ocr_lang", - os.getenv("DOCLING_OCR_LANG", "eng,fra,deu,spa"), -) - -DOCLING_PDF_BACKEND = PersistentConfig( - "DOCLING_PDF_BACKEND", - "rag.docling_pdf_backend", - os.getenv("DOCLING_PDF_BACKEND", "dlparse_v4"), -) - -DOCLING_TABLE_MODE = PersistentConfig( - "DOCLING_TABLE_MODE", - "rag.docling_table_mode", - os.getenv("DOCLING_TABLE_MODE", "accurate"), -) - -DOCLING_PIPELINE = PersistentConfig( - "DOCLING_PIPELINE", - "rag.docling_pipeline", - os.getenv("DOCLING_PIPELINE", "standard"), -) - -DOCLING_DO_PICTURE_DESCRIPTION = PersistentConfig( - "DOCLING_DO_PICTURE_DESCRIPTION", - "rag.docling_do_picture_description", - os.getenv("DOCLING_DO_PICTURE_DESCRIPTION", "False").lower() == "true", -) - -DOCLING_PICTURE_DESCRIPTION_MODE = PersistentConfig( - "DOCLING_PICTURE_DESCRIPTION_MODE", - "rag.docling_picture_description_mode", - os.getenv("DOCLING_PICTURE_DESCRIPTION_MODE", ""), -) - - -docling_picture_description_local = os.getenv("DOCLING_PICTURE_DESCRIPTION_LOCAL", "") -try: - docling_picture_description_local = json.loads(docling_picture_description_local) -except json.JSONDecodeError: - docling_picture_description_local = {} - - -DOCLING_PICTURE_DESCRIPTION_LOCAL = PersistentConfig( - "DOCLING_PICTURE_DESCRIPTION_LOCAL", - "rag.docling_picture_description_local", - docling_picture_description_local, -) - -docling_picture_description_api = os.getenv("DOCLING_PICTURE_DESCRIPTION_API", "") -try: - docling_picture_description_api = json.loads(docling_picture_description_api) -except json.JSONDecodeError: - docling_picture_description_api = {} - - -DOCLING_PICTURE_DESCRIPTION_API = PersistentConfig( - "DOCLING_PICTURE_DESCRIPTION_API", - "rag.docling_picture_description_api", - docling_picture_description_api, -) - - DOCUMENT_INTELLIGENCE_ENDPOINT = PersistentConfig( "DOCUMENT_INTELLIGENCE_ENDPOINT", "rag.document_intelligence_endpoint", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index b14c18947c..8219943408 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -268,18 +268,8 @@ from open_webui.config import ( EXTERNAL_DOCUMENT_LOADER_API_KEY, TIKA_SERVER_URL, DOCLING_SERVER_URL, + DOCLING_API_KEY, DOCLING_PARAMS, - DOCLING_DO_OCR, - DOCLING_FORCE_OCR, - DOCLING_OCR_ENGINE, - DOCLING_OCR_LANG, - DOCLING_PDF_BACKEND, - DOCLING_TABLE_MODE, - DOCLING_PIPELINE, - DOCLING_DO_PICTURE_DESCRIPTION, - DOCLING_PICTURE_DESCRIPTION_MODE, - DOCLING_PICTURE_DESCRIPTION_LOCAL, - DOCLING_PICTURE_DESCRIPTION_API, DOCUMENT_INTELLIGENCE_ENDPOINT, DOCUMENT_INTELLIGENCE_KEY, MISTRAL_OCR_API_BASE_URL, @@ -874,18 +864,8 @@ app.state.config.EXTERNAL_DOCUMENT_LOADER_URL = EXTERNAL_DOCUMENT_LOADER_URL app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY = EXTERNAL_DOCUMENT_LOADER_API_KEY app.state.config.TIKA_SERVER_URL = TIKA_SERVER_URL app.state.config.DOCLING_SERVER_URL = DOCLING_SERVER_URL +app.state.config.DOCLING_API_KEY = DOCLING_API_KEY app.state.config.DOCLING_PARAMS = DOCLING_PARAMS -app.state.config.DOCLING_DO_OCR = DOCLING_DO_OCR -app.state.config.DOCLING_FORCE_OCR = DOCLING_FORCE_OCR -app.state.config.DOCLING_OCR_ENGINE = DOCLING_OCR_ENGINE -app.state.config.DOCLING_OCR_LANG = DOCLING_OCR_LANG -app.state.config.DOCLING_PDF_BACKEND = DOCLING_PDF_BACKEND -app.state.config.DOCLING_TABLE_MODE = DOCLING_TABLE_MODE -app.state.config.DOCLING_PIPELINE = DOCLING_PIPELINE -app.state.config.DOCLING_DO_PICTURE_DESCRIPTION = DOCLING_DO_PICTURE_DESCRIPTION -app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE = DOCLING_PICTURE_DESCRIPTION_MODE -app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL = DOCLING_PICTURE_DESCRIPTION_LOCAL -app.state.config.DOCLING_PICTURE_DESCRIPTION_API = DOCLING_PICTURE_DESCRIPTION_API app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = DOCUMENT_INTELLIGENCE_ENDPOINT app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY app.state.config.MISTRAL_OCR_API_BASE_URL = MISTRAL_OCR_API_BASE_URL diff --git a/backend/open_webui/retrieval/loaders/main.py b/backend/open_webui/retrieval/loaders/main.py index bbc3da9bc9..fcc507e088 100644 --- a/backend/open_webui/retrieval/loaders/main.py +++ b/backend/open_webui/retrieval/loaders/main.py @@ -132,8 +132,9 @@ class TikaLoader: class DoclingLoader: - def __init__(self, url, file_path=None, mime_type=None, params=None): + def __init__(self, url, api_key=None, file_path=None, mime_type=None, params=None): self.url = url.rstrip("/") + self.api_key = api_key self.file_path = file_path self.mime_type = mime_type @@ -141,6 +142,10 @@ class DoclingLoader: def load(self) -> list[Document]: with open(self.file_path, "rb") as f: + headers = {} + if self.api_key: + headers["Authorization"] = f"Bearer {self.api_key}" + files = { "files": ( self.file_path, @@ -149,60 +154,15 @@ class DoclingLoader: ) } - params = {"image_export_mode": "placeholder"} - - if self.params: - if self.params.get("do_picture_description"): - params["do_picture_description"] = self.params.get( - "do_picture_description" - ) - - picture_description_mode = self.params.get( - "picture_description_mode", "" - ).lower() - - if picture_description_mode == "local" and self.params.get( - "picture_description_local", {} - ): - params["picture_description_local"] = json.dumps( - self.params.get("picture_description_local", {}) - ) - - elif picture_description_mode == "api" and self.params.get( - "picture_description_api", {} - ): - params["picture_description_api"] = json.dumps( - self.params.get("picture_description_api", {}) - ) - - params["do_ocr"] = self.params.get("do_ocr") - - params["force_ocr"] = self.params.get("force_ocr") - - if ( - self.params.get("do_ocr") - and self.params.get("ocr_engine") - and self.params.get("ocr_lang") - ): - params["ocr_engine"] = self.params.get("ocr_engine") - params["ocr_lang"] = [ - lang.strip() - for lang in self.params.get("ocr_lang").split(",") - if lang.strip() - ] - - if self.params.get("pdf_backend"): - params["pdf_backend"] = self.params.get("pdf_backend") - - if self.params.get("table_mode"): - params["table_mode"] = self.params.get("table_mode") - - if self.params.get("pipeline"): - params["pipeline"] = self.params.get("pipeline") - - endpoint = f"{self.url}/v1/convert/file" - r = requests.post(endpoint, files=files, data=params) - + r = requests.post( + f"{self.url}/v1/convert/file", + files=files, + data={ + "image_export_mode": "placeholder", + **self.params, + }, + headers=headers, + ) if r.ok: result = r.json() document_data = result.get("document", {}) @@ -211,7 +171,6 @@ class DoclingLoader: metadata = {"Content-Type": self.mime_type} if self.mime_type else {} log.debug("Docling extracted text: %s", text) - return [Document(page_content=text, metadata=metadata)] else: error_msg = f"Error calling Docling API: {r.reason}" @@ -340,6 +299,7 @@ class Loader: loader = DoclingLoader( url=self.kwargs.get("DOCLING_SERVER_URL"), + api_key=self.kwargs.get("DOCLING_API_KEY", None), file_path=file_path, mime_type=file_content_type, params=params, diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 358b8aca49..e3191eb0bd 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -453,18 +453,8 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): "EXTERNAL_DOCUMENT_LOADER_API_KEY": request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY, "TIKA_SERVER_URL": request.app.state.config.TIKA_SERVER_URL, "DOCLING_SERVER_URL": request.app.state.config.DOCLING_SERVER_URL, + "DOCLING_API_KEY": request.app.state.config.DOCLING_API_KEY, "DOCLING_PARAMS": request.app.state.config.DOCLING_PARAMS, - "DOCLING_DO_OCR": request.app.state.config.DOCLING_DO_OCR, - "DOCLING_FORCE_OCR": request.app.state.config.DOCLING_FORCE_OCR, - "DOCLING_OCR_ENGINE": request.app.state.config.DOCLING_OCR_ENGINE, - "DOCLING_OCR_LANG": request.app.state.config.DOCLING_OCR_LANG, - "DOCLING_PDF_BACKEND": request.app.state.config.DOCLING_PDF_BACKEND, - "DOCLING_TABLE_MODE": request.app.state.config.DOCLING_TABLE_MODE, - "DOCLING_PIPELINE": request.app.state.config.DOCLING_PIPELINE, - "DOCLING_DO_PICTURE_DESCRIPTION": request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION, - "DOCLING_PICTURE_DESCRIPTION_MODE": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE, - "DOCLING_PICTURE_DESCRIPTION_LOCAL": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL, - "DOCLING_PICTURE_DESCRIPTION_API": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_API, "DOCUMENT_INTELLIGENCE_ENDPOINT": request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT, "DOCUMENT_INTELLIGENCE_KEY": request.app.state.config.DOCUMENT_INTELLIGENCE_KEY, "MISTRAL_OCR_API_BASE_URL": request.app.state.config.MISTRAL_OCR_API_BASE_URL, @@ -642,18 +632,8 @@ class ConfigForm(BaseModel): TIKA_SERVER_URL: Optional[str] = None DOCLING_SERVER_URL: Optional[str] = None + DOCLING_API_KEY: Optional[str] = None DOCLING_PARAMS: Optional[dict] = None - DOCLING_DO_OCR: Optional[bool] = None - DOCLING_FORCE_OCR: Optional[bool] = None - DOCLING_OCR_ENGINE: Optional[str] = None - DOCLING_OCR_LANG: Optional[str] = None - DOCLING_PDF_BACKEND: Optional[str] = None - DOCLING_TABLE_MODE: Optional[str] = None - DOCLING_PIPELINE: Optional[str] = None - DOCLING_DO_PICTURE_DESCRIPTION: Optional[bool] = None - DOCLING_PICTURE_DESCRIPTION_MODE: Optional[str] = None - DOCLING_PICTURE_DESCRIPTION_LOCAL: Optional[dict] = None - DOCLING_PICTURE_DESCRIPTION_API: Optional[dict] = None DOCUMENT_INTELLIGENCE_ENDPOINT: Optional[str] = None DOCUMENT_INTELLIGENCE_KEY: Optional[str] = None MISTRAL_OCR_API_BASE_URL: Optional[str] = None @@ -831,68 +811,16 @@ async def update_rag_config( if form_data.DOCLING_SERVER_URL is not None else request.app.state.config.DOCLING_SERVER_URL ) + request.app.state.config.DOCLING_API_KEY = ( + form_data.DOCLING_API_KEY + if form_data.DOCLING_API_KEY is not None + else request.app.state.config.DOCLING_API_KEY + ) request.app.state.config.DOCLING_PARAMS = ( form_data.DOCLING_PARAMS if form_data.DOCLING_PARAMS is not None else request.app.state.config.DOCLING_PARAMS ) - request.app.state.config.DOCLING_DO_OCR = ( - form_data.DOCLING_DO_OCR - if form_data.DOCLING_DO_OCR is not None - else request.app.state.config.DOCLING_DO_OCR - ) - request.app.state.config.DOCLING_FORCE_OCR = ( - form_data.DOCLING_FORCE_OCR - if form_data.DOCLING_FORCE_OCR is not None - else request.app.state.config.DOCLING_FORCE_OCR - ) - request.app.state.config.DOCLING_OCR_ENGINE = ( - form_data.DOCLING_OCR_ENGINE - if form_data.DOCLING_OCR_ENGINE is not None - else request.app.state.config.DOCLING_OCR_ENGINE - ) - request.app.state.config.DOCLING_OCR_LANG = ( - form_data.DOCLING_OCR_LANG - if form_data.DOCLING_OCR_LANG is not None - else request.app.state.config.DOCLING_OCR_LANG - ) - request.app.state.config.DOCLING_PDF_BACKEND = ( - form_data.DOCLING_PDF_BACKEND - if form_data.DOCLING_PDF_BACKEND is not None - else request.app.state.config.DOCLING_PDF_BACKEND - ) - request.app.state.config.DOCLING_TABLE_MODE = ( - form_data.DOCLING_TABLE_MODE - if form_data.DOCLING_TABLE_MODE is not None - else request.app.state.config.DOCLING_TABLE_MODE - ) - request.app.state.config.DOCLING_PIPELINE = ( - form_data.DOCLING_PIPELINE - if form_data.DOCLING_PIPELINE is not None - else request.app.state.config.DOCLING_PIPELINE - ) - request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION = ( - form_data.DOCLING_DO_PICTURE_DESCRIPTION - if form_data.DOCLING_DO_PICTURE_DESCRIPTION is not None - else request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION - ) - - request.app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE = ( - form_data.DOCLING_PICTURE_DESCRIPTION_MODE - if form_data.DOCLING_PICTURE_DESCRIPTION_MODE is not None - else request.app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE - ) - request.app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL = ( - form_data.DOCLING_PICTURE_DESCRIPTION_LOCAL - if form_data.DOCLING_PICTURE_DESCRIPTION_LOCAL is not None - else request.app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL - ) - request.app.state.config.DOCLING_PICTURE_DESCRIPTION_API = ( - form_data.DOCLING_PICTURE_DESCRIPTION_API - if form_data.DOCLING_PICTURE_DESCRIPTION_API is not None - else request.app.state.config.DOCLING_PICTURE_DESCRIPTION_API - ) - request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = ( form_data.DOCUMENT_INTELLIGENCE_ENDPOINT if form_data.DOCUMENT_INTELLIGENCE_ENDPOINT is not None @@ -1189,18 +1117,8 @@ async def update_rag_config( "EXTERNAL_DOCUMENT_LOADER_API_KEY": request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY, "TIKA_SERVER_URL": request.app.state.config.TIKA_SERVER_URL, "DOCLING_SERVER_URL": request.app.state.config.DOCLING_SERVER_URL, + "DOCLING_API_KEY": request.app.state.config.DOCLING_API_KEY, "DOCLING_PARAMS": request.app.state.config.DOCLING_PARAMS, - "DOCLING_DO_OCR": request.app.state.config.DOCLING_DO_OCR, - "DOCLING_FORCE_OCR": request.app.state.config.DOCLING_FORCE_OCR, - "DOCLING_OCR_ENGINE": request.app.state.config.DOCLING_OCR_ENGINE, - "DOCLING_OCR_LANG": request.app.state.config.DOCLING_OCR_LANG, - "DOCLING_PDF_BACKEND": request.app.state.config.DOCLING_PDF_BACKEND, - "DOCLING_TABLE_MODE": request.app.state.config.DOCLING_TABLE_MODE, - "DOCLING_PIPELINE": request.app.state.config.DOCLING_PIPELINE, - "DOCLING_DO_PICTURE_DESCRIPTION": request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION, - "DOCLING_PICTURE_DESCRIPTION_MODE": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE, - "DOCLING_PICTURE_DESCRIPTION_LOCAL": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL, - "DOCLING_PICTURE_DESCRIPTION_API": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_API, "DOCUMENT_INTELLIGENCE_ENDPOINT": request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT, "DOCUMENT_INTELLIGENCE_KEY": request.app.state.config.DOCUMENT_INTELLIGENCE_KEY, "MISTRAL_OCR_API_BASE_URL": request.app.state.config.MISTRAL_OCR_API_BASE_URL, @@ -1607,20 +1525,8 @@ def process_file( EXTERNAL_DOCUMENT_LOADER_API_KEY=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY, TIKA_SERVER_URL=request.app.state.config.TIKA_SERVER_URL, DOCLING_SERVER_URL=request.app.state.config.DOCLING_SERVER_URL, - DOCLING_PARAMS={ - "do_ocr": request.app.state.config.DOCLING_DO_OCR, - "force_ocr": request.app.state.config.DOCLING_FORCE_OCR, - "ocr_engine": request.app.state.config.DOCLING_OCR_ENGINE, - "ocr_lang": request.app.state.config.DOCLING_OCR_LANG, - "pdf_backend": request.app.state.config.DOCLING_PDF_BACKEND, - "table_mode": request.app.state.config.DOCLING_TABLE_MODE, - "pipeline": request.app.state.config.DOCLING_PIPELINE, - "do_picture_description": request.app.state.config.DOCLING_DO_PICTURE_DESCRIPTION, - "picture_description_mode": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE, - "picture_description_local": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL, - "picture_description_api": request.app.state.config.DOCLING_PICTURE_DESCRIPTION_API, - **request.app.state.config.DOCLING_PARAMS, - }, + DOCLING_API_KEY=request.app.state.config.DOCLING_API_KEY, + DOCLING_PARAMS=request.app.state.config.DOCLING_PARAMS, PDF_EXTRACT_IMAGES=request.app.state.config.PDF_EXTRACT_IMAGES, DOCUMENT_INTELLIGENCE_ENDPOINT=request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT, DOCUMENT_INTELLIGENCE_KEY=request.app.state.config.DOCUMENT_INTELLIGENCE_KEY, diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index 83369ac993..5c449fc869 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -151,26 +151,6 @@ toast.error($i18n.t('Docling Server URL required.')); return; } - if ( - RAGConfig.CONTENT_EXTRACTION_ENGINE === 'docling' && - RAGConfig.DOCLING_DO_OCR && - ((RAGConfig.DOCLING_OCR_ENGINE === '' && RAGConfig.DOCLING_OCR_LANG !== '') || - (RAGConfig.DOCLING_OCR_ENGINE !== '' && RAGConfig.DOCLING_OCR_LANG === '')) - ) { - toast.error( - $i18n.t('Both Docling OCR Engine and Language(s) must be provided or both left empty.') - ); - return; - } - if ( - RAGConfig.CONTENT_EXTRACTION_ENGINE === 'docling' && - RAGConfig.DOCLING_DO_OCR === false && - RAGConfig.DOCLING_FORCE_OCR === true - ) { - toast.error($i18n.t('In order to force OCR, performing OCR must be enabled.')); - return; - } - if ( RAGConfig.CONTENT_EXTRACTION_ENGINE === 'datalab_marker' && RAGConfig.DATALAB_MARKER_ADDITIONAL_CONFIG && @@ -238,12 +218,6 @@ ALLOWED_FILE_EXTENSIONS: RAGConfig.ALLOWED_FILE_EXTENSIONS.split(',') .map((ext) => ext.trim()) .filter((ext) => ext !== ''), - DOCLING_PICTURE_DESCRIPTION_LOCAL: JSON.parse( - RAGConfig.DOCLING_PICTURE_DESCRIPTION_LOCAL || '{}' - ), - DOCLING_PICTURE_DESCRIPTION_API: JSON.parse( - RAGConfig.DOCLING_PICTURE_DESCRIPTION_API || '{}' - ), DOCLING_PARAMS: typeof RAGConfig.DOCLING_PARAMS === 'string' && RAGConfig.DOCLING_PARAMS.trim() !== '' ? JSON.parse(RAGConfig.DOCLING_PARAMS) @@ -281,16 +255,6 @@ const config = await getRAGConfig(localStorage.token); config.ALLOWED_FILE_EXTENSIONS = (config?.ALLOWED_FILE_EXTENSIONS ?? []).join(', '); - config.DOCLING_PICTURE_DESCRIPTION_LOCAL = JSON.stringify( - config.DOCLING_PICTURE_DESCRIPTION_LOCAL ?? {}, - null, - 2 - ); - config.DOCLING_PICTURE_DESCRIPTION_API = JSON.stringify( - config.DOCLING_PICTURE_DESCRIPTION_API ?? {}, - null, - 2 - ); config.DOCLING_PARAMS = typeof config.DOCLING_PARAMS === 'object' ? JSON.stringify(config.DOCLING_PARAMS ?? {}, null, 2) @@ -589,174 +553,19 @@ {:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'docling'} -
+
+
-
-
-
- {$i18n.t('Perform OCR')} -
-
- -
-
-
- {#if RAGConfig.DOCLING_DO_OCR} -
- - -
- {/if} -
-
-
- {$i18n.t('Force OCR')} -
-
- -
-
-
-
-
- - {$i18n.t('PDF Backend')} - -
-
- -
-
-
-
- - {$i18n.t('Table Mode')} - -
-
- -
-
-
-
- - {$i18n.t('Pipeline')} - -
-
- -
-
-
-
-
- {$i18n.t('Describe Pictures in Documents')} -
-
- -
-
-
- {#if RAGConfig.DOCLING_DO_PICTURE_DESCRIPTION} -
-
- - {$i18n.t('Picture Description Mode')} - -
-
- -
-
- - {#if RAGConfig.DOCLING_PICTURE_DESCRIPTION_MODE === 'local'} -
-
-
- {$i18n.t('Picture Description Local Config')} -
-
- -