From c7d76b4ceec778675e06befd97974d49ea3ac590 Mon Sep 17 00:00:00 2001 From: Saifeddine ALOUI Date: Mon, 17 Mar 2025 10:21:01 +0100 Subject: [PATCH 1/3] Create anthropic.py --- lightrag/llm/anthropic.py | 271 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 lightrag/llm/anthropic.py diff --git a/lightrag/llm/anthropic.py b/lightrag/llm/anthropic.py new file mode 100644 index 00000000..8e38395e --- /dev/null +++ b/lightrag/llm/anthropic.py @@ -0,0 +1,271 @@ +from ..utils import verbose_debug, VERBOSE_DEBUG +import sys +import os +import logging +import numpy as np +from typing import Any, Union, AsyncIterator +import pipmaster as pm # Pipmaster for dynamic library install + +if sys.version_info < (3, 9): + from typing import AsyncIterator +else: + from collections.abc import AsyncIterator + +# Install Anthropic SDK if not present +if not pm.is_installed("anthropic"): + pm.install("anthropic") + +# Add Voyage AI import +if not pm.is_installed("voyageai"): + pm.install("voyageai") +import voyageai + +from anthropic import ( + AsyncAnthropic, + APIConnectionError, + RateLimitError, + APITimeoutError, +) +from tenacity import ( + retry, + stop_after_attempt, + wait_exponential, + retry_if_exception_type, +) +from lightrag.utils import ( + safe_unicode_decode, + logger, +) +from lightrag.api import __api_version__ + +# Custom exception for retry mechanism +class InvalidResponseError(Exception): + """Custom exception class for triggering retry mechanism""" + pass + +# Core Anthropic completion function with retry +@retry( + stop=stop_after_attempt(3), + wait=wait_exponential(multiplier=1, min=4, max=10), + retry=retry_if_exception_type( + (RateLimitError, APIConnectionError, APITimeoutError, InvalidResponseError) + ), +) +async def anthropic_complete_if_cache( + model: str, + prompt: str, + system_prompt: str | None = None, + history_messages: list[dict[str, Any]] | None = None, + base_url: str | None = None, + api_key: str | None = None, + **kwargs: Any, +) -> Union[str, AsyncIterator[str]]: + if history_messages is None: + history_messages = [] + if not api_key: + api_key = os.environ.get("ANTHROPIC_API_KEY") + + default_headers = { + "User-Agent": f"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_8) LightRAG/{__api_version__}", + "Content-Type": "application/json", + } + + # Set logger level to INFO when VERBOSE_DEBUG is off + if not VERBOSE_DEBUG and logger.level == logging.DEBUG: + logging.getLogger("anthropic").setLevel(logging.INFO) + + anthropic_async_client = ( + AsyncAnthropic(default_headers=default_headers, api_key=api_key) + if base_url is None + else AsyncAnthropic( + base_url=base_url, default_headers=default_headers, api_key=api_key + ) + ) + kwargs.pop("hashing_kv", None) + messages: list[dict[str, Any]] = [] + if system_prompt: + messages.append({"role": "system", "content": system_prompt}) + messages.extend(history_messages) + messages.append({"role": "user", "content": prompt}) + + logger.debug("===== Sending Query to Anthropic LLM =====") + logger.debug(f"Model: {model} Base URL: {base_url}") + logger.debug(f"Additional kwargs: {kwargs}") + verbose_debug(f"Query: {prompt}") + verbose_debug(f"System prompt: {system_prompt}") + + try: + response = await anthropic_async_client.messages.create( + model=model, + messages=messages, + stream=True, + **kwargs + ) + except APIConnectionError as e: + logger.error(f"Anthropic API Connection Error: {e}") + raise + except RateLimitError as e: + logger.error(f"Anthropic API Rate Limit Error: {e}") + raise + except APITimeoutError as e: + logger.error(f"Anthropic API Timeout Error: {e}") + raise + except Exception as e: + logger.error( + f"Anthropic API Call Failed,\nModel: {model},\nParams: {kwargs}, Got: {e}" + ) + raise + + async def stream_response(): + try: + async for event in response: + content = event.delta.text if hasattr(event, "delta") and event.delta.text else None + if content is None: + continue + if r"\u" in content: + content = safe_unicode_decode(content.encode("utf-8")) + yield content + except Exception as e: + logger.error(f"Error in stream response: {str(e)}") + raise + + return stream_response() + +# Generic Anthropic completion function +async def anthropic_complete( + prompt: str, + system_prompt: str | None = None, + history_messages: list[dict[str, Any]] | None = None, + **kwargs: Any, +) -> Union[str, AsyncIterator[str]]: + if history_messages is None: + history_messages = [] + model_name = kwargs["hashing_kv"].global_config["llm_model_name"] + return await anthropic_complete_if_cache( + model_name, + prompt, + system_prompt=system_prompt, + history_messages=history_messages, + **kwargs, + ) + +# Claude 3 Opus specific completion +async def claude_3_opus_complete( + prompt: str, + system_prompt: str | None = None, + history_messages: list[dict[str, Any]] | None = None, + **kwargs: Any, +) -> Union[str, AsyncIterator[str]]: + if history_messages is None: + history_messages = [] + return await anthropic_complete_if_cache( + "claude-3-opus-20240229", + prompt, + system_prompt=system_prompt, + history_messages=history_messages, + **kwargs, + ) + +# Claude 3 Sonnet specific completion +async def claude_3_sonnet_complete( + prompt: str, + system_prompt: str | None = None, + history_messages: list[dict[str, Any]] | None = None, + **kwargs: Any, +) -> Union[str, AsyncIterator[str]]: + if history_messages is None: + history_messages = [] + return await anthropic_complete_if_cache( + "claude-3-sonnet-20240229", + prompt, + system_prompt=system_prompt, + history_messages=history_messages, + **kwargs, + ) + +# Claude 3 Haiku specific completion +async def claude_3_haiku_complete( + prompt: str, + system_prompt: str | None = None, + history_messages: list[dict[str, Any]] | None = None, + **kwargs: Any, +) -> Union[str, AsyncIterator[str]]: + if history_messages is None: + history_messages = [] + return await anthropic_complete_if_cache( + "claude-3-haiku-20240307", + prompt, + system_prompt=system_prompt, + history_messages=history_messages, + **kwargs, + ) + +# Embedding function (placeholder, as Anthropic does not provide embeddings) +@retry( + stop=stop_after_attempt(3), + wait=wait_exponential(multiplier=1, min=4, max=60), + retry=retry_if_exception_type( + (RateLimitError, APIConnectionError, APITimeoutError) + ), +) +async def anthropic_embed( + texts: list[str], + model: str = "voyage-3", # Default to voyage-3 as a good general-purpose model + base_url: str = None, + api_key: str = None, +) -> np.ndarray: + """ + Generate embeddings using Voyage AI since Anthropic doesn't provide native embedding support. + + Args: + texts: List of text strings to embed + model: Voyage AI model name (e.g., "voyage-3", "voyage-3-large", "voyage-code-3") + base_url: Optional custom base URL (not used for Voyage AI) + api_key: API key for Voyage AI (defaults to VOYAGE_API_KEY environment variable) + + Returns: + numpy array of shape (len(texts), embedding_dimension) containing the embeddings + """ + if not api_key: + api_key = os.environ.get("VOYAGE_API_KEY") + if not api_key: + logger.error("VOYAGE_API_KEY environment variable not set") + raise ValueError("VOYAGE_API_KEY environment variable is required for embeddings") + + try: + # Initialize Voyage AI client + voyage_client = voyageai.Client(api_key=api_key) + + # Get embeddings + result = voyage_client.embed( + texts, + model=model, + input_type="document" # Assuming document context; could be made configurable + ) + + # Convert list of embeddings to numpy array + embeddings = np.array(result.embeddings, dtype=np.float32) + + logger.debug(f"Generated embeddings for {len(texts)} texts using {model}") + verbose_debug(f"Embedding shape: {embeddings.shape}") + + return embeddings + + except Exception as e: + logger.error(f"Voyage AI embedding failed: {str(e)}") + raise + +# Optional: a helper function to get available embedding models +def get_available_embedding_models() -> dict[str, dict]: + """ + Returns a dictionary of available Voyage AI embedding models and their properties. + """ + return { + "voyage-3-large": {"context_length": 32000, "dimension": 1024, "description": "Best general-purpose and multilingual"}, + "voyage-3": {"context_length": 32000, "dimension": 1024, "description": "General-purpose and multilingual"}, + "voyage-3-lite": {"context_length": 32000, "dimension": 512, "description": "Optimized for latency and cost"}, + "voyage-code-3": {"context_length": 32000, "dimension": 1024, "description": "Optimized for code"}, + "voyage-finance-2": {"context_length": 32000, "dimension": 1024, "description": "Optimized for finance"}, + "voyage-law-2": {"context_length": 16000, "dimension": 1024, "description": "Optimized for legal"}, + "voyage-multimodal-3": {"context_length": 32000, "dimension": 1024, "description": "Multimodal text and images"}, + } From 5470f9dfee646106d09a766cb64c44a195a265d2 Mon Sep 17 00:00:00 2001 From: Saifeddine ALOUI Date: Mon, 17 Mar 2025 18:56:50 +0100 Subject: [PATCH 2/3] added arabic locale --- lightrag_webui/src/locales/ar.json | 239 +++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 lightrag_webui/src/locales/ar.json diff --git a/lightrag_webui/src/locales/ar.json b/lightrag_webui/src/locales/ar.json new file mode 100644 index 00000000..6b0234cf --- /dev/null +++ b/lightrag_webui/src/locales/ar.json @@ -0,0 +1,239 @@ +{ + "settings": { + "language": "اللغة", + "theme": "السمة", + "light": "فاتح", + "dark": "داكن", + "system": "النظام" + }, + "header": { + "documents": "المستندات", + "knowledgeGraph": "شبكة المعرفة", + "retrieval": "الاسترجاع", + "api": "واجهة برمجة التطبيقات", + "projectRepository": "مستودع المشروع", + "themeToggle": { + "switchToLight": "التحويل إلى السمة الفاتحة", + "switchToDark": "التحويل إلى السمة الداكنة" + } + }, + "documentPanel": { + "clearDocuments": { + "button": "مسح", + "tooltip": "مسح المستندات", + "title": "مسح المستندات", + "confirm": "هل تريد حقًا مسح جميع المستندات؟", + "confirmButton": "نعم", + "success": "تم مسح المستندات بنجاح", + "failed": "فشل مسح المستندات:\n{{message}}", + "error": "فشل مسح المستندات:\n{{error}}" + }, + "uploadDocuments": { + "button": "رفع", + "tooltip": "رفع المستندات", + "title": "رفع المستندات", + "description": "اسحب وأفلت مستنداتك هنا أو انقر للتصفح.", + "uploading": "جارٍ الرفع {{name}}: {{percent}}%", + "success": "نجاح الرفع:\nتم رفع {{name}} بنجاح", + "failed": "فشل الرفع:\n{{name}}\n{{message}}", + "error": "فشل الرفع:\n{{name}}\n{{error}}", + "generalError": "فشل الرفع\n{{error}}", + "fileTypes": "الأنواع المدعومة: TXT، MD، DOCX، PDF، PPTX، RTF، ODT، EPUB، HTML، HTM، TEX، JSON، XML، YAML، YML، CSV، LOG، CONF، INI، PROPERTIES، SQL، BAT، SH، C، CPP، PY، JAVA، JS، TS، SWIFT، GO، RB، PHP، CSS، SCSS، LESS" + }, + "documentManager": { + "title": "إدارة المستندات", + "scanButton": "مسح ضوئي", + "scanTooltip": "مسح المستندات ضوئيًا", + "uploadedTitle": "المستندات المرفوعة", + "uploadedDescription": "قائمة المستندات المرفوعة وحالاتها.", + "emptyTitle": "لا توجد مستندات", + "emptyDescription": "لا توجد مستندات مرفوعة بعد.", + "columns": { + "id": "المعرف", + "summary": "الملخص", + "status": "الحالة", + "length": "الطول", + "chunks": "الأجزاء", + "created": "تم الإنشاء", + "updated": "تم التحديث", + "metadata": "البيانات الوصفية" + }, + "status": { + "completed": "مكتمل", + "processing": "قيد المعالجة", + "pending": "معلق", + "failed": "فشل" + }, + "errors": { + "loadFailed": "فشل تحميل المستندات\n{{error}}", + "scanFailed": "فشل المسح الضوئي للمستندات\n{{error}}", + "scanProgressFailed": "فشل الحصول على تقدم المسح الضوئي\n{{error}}" + } + } + }, + "graphPanel": { + "sideBar": { + "settings": { + "settings": "الإعدادات", + "healthCheck": "فحص الحالة", + "showPropertyPanel": "إظهار لوحة الخصائص", + "showSearchBar": "إظهار شريط البحث", + "showNodeLabel": "إظهار تسمية العقدة", + "nodeDraggable": "العقدة قابلة للسحب", + "showEdgeLabel": "إظهار تسمية الحافة", + "hideUnselectedEdges": "إخفاء الحواف غير المحددة", + "edgeEvents": "أحداث الحافة", + "maxQueryDepth": "أقصى عمق للاستعلام", + "minDegree": "الدرجة الدنيا", + "maxLayoutIterations": "أقصى تكرارات التخطيط", + "depth": "العمق", + "degree": "الدرجة", + "apiKey": "مفتاح واجهة برمجة التطبيقات", + "enterYourAPIkey": "أدخل مفتاح واجهة برمجة التطبيقات الخاص بك", + "save": "حفظ", + "refreshLayout": "تحديث التخطيط" + }, + "zoomControl": { + "zoomIn": "تكبير", + "zoomOut": "تصغير", + "resetZoom": "إعادة تعيين التكبير" + }, + "layoutsControl": { + "startAnimation": "بدء حركة التخطيط", + "stopAnimation": "إيقاف حركة التخطيط", + "layoutGraph": "تخطيط الرسم البياني", + "layouts": { + "Circular": "دائري", + "Circlepack": "حزمة دائرية", + "Random": "عشوائي", + "Noverlaps": "بدون تداخل", + "Force Directed": "موجه بالقوة", + "Force Atlas": "أطلس القوة" + } + }, + "fullScreenControl": { + "fullScreen": "شاشة كاملة", + "windowed": "نوافذ" + } + }, + "statusIndicator": { + "connected": "متصل", + "disconnected": "غير متصل" + }, + "statusCard": { + "unavailable": "معلومات الحالة غير متوفرة", + "storageInfo": "معلومات التخزين", + "workingDirectory": "دليل العمل", + "inputDirectory": "دليل الإدخال", + "llmConfig": "تكوين نموذج اللغة الكبير", + "llmBinding": "ربط نموذج اللغة الكبير", + "llmBindingHost": "مضيف ربط نموذج اللغة الكبير", + "llmModel": "نموذج اللغة الكبير", + "maxTokens": "أقصى عدد من الرموز", + "embeddingConfig": "تكوين التضمين", + "embeddingBinding": "ربط التضمين", + "embeddingBindingHost": "مضيف ربط التضمين", + "embeddingModel": "نموذج التضمين", + "storageConfig": "تكوين التخزين", + "kvStorage": "تخزين المفتاح-القيمة", + "docStatusStorage": "تخزين حالة المستند", + "graphStorage": "تخزين الرسم البياني", + "vectorStorage": "تخزين المتجهات" + }, + "propertiesView": { + "node": { + "title": "عقدة", + "id": "المعرف", + "labels": "التسميات", + "degree": "الدرجة", + "properties": "الخصائص", + "relationships": "العلاقات", + "propertyNames": { + "description": "الوصف", + "entity_id": "الاسم", + "entity_type": "النوع", + "source_id": "معرف المصدر", + "Neighbour": "الجار" + } + }, + "edge": { + "title": "علاقة", + "id": "المعرف", + "type": "النوع", + "source": "المصدر", + "target": "الهدف", + "properties": "الخصائص" + } + }, + "search": { + "placeholder": "ابحث في العقد...", + "message": "و {{count}} آخرون" + }, + "graphLabels": { + "selectTooltip": "حدد تسمية الاستعلام", + "noLabels": "لم يتم العثور على تسميات", + "label": "التسمية", + "placeholder": "ابحث في التسميات...", + "andOthers": "و {{count}} آخرون" + } + }, + "retrievePanel": { + "chatMessage": { + "copyTooltip": "نسخ إلى الحافظة", + "copyError": "فشل نسخ النص إلى الحافظة" + }, + "retrieval": { + "startPrompt": "ابدأ الاسترجاع بكتابة استفسارك أدناه", + "clear": "مسح", + "send": "إرسال", + "placeholder": "اكتب استفسارك...", + "error": "خطأ: فشل الحصول على الرد" + }, + "querySettings": { + "parametersTitle": "المعلمات", + "parametersDescription": "تكوين معلمات الاستعلام الخاص بك", + "queryMode": "وضع الاستعلام", + "queryModeTooltip": "حدد استراتيجية الاسترجاع:\n• ساذج: بحث أساسي بدون تقنيات متقدمة\n• محلي: استرجاع معلومات يعتمد على السياق\n• عالمي: يستخدم قاعدة المعرفة العالمية\n• مختلط: يجمع بين الاسترجاع المحلي والعالمي\n• مزيج: يدمج شبكة المعرفة مع الاسترجاع المتجهي", + "queryModeOptions": { + "naive": "ساذج", + "local": "محلي", + "global": "عالمي", + "hybrid": "مختلط", + "mix": "مزيج" + }, + "responseFormat": "تنسيق الرد", + "responseFormatTooltip": "يحدد تنسيق الرد. أمثلة:\n• فقرات متعددة\n• فقرة واحدة\n• نقاط نقطية", + "responseFormatOptions": { + "multipleParagraphs": "فقرات متعددة", + "singleParagraph": "فقرة واحدة", + "bulletPoints": "نقاط نقطية" + }, + "topK": "أعلى K نتائج", + "topKTooltip": "عدد العناصر العلوية للاسترجاع. يمثل الكيانات في وضع 'محلي' والعلاقات في وضع 'عالمي'", + "topKPlaceholder": "عدد النتائج", + "maxTokensTextUnit": "أقصى عدد من الرموز لوحدة النص", + "maxTokensTextUnitTooltip": "الحد الأقصى لعدد الرموز المسموح به لكل جزء نصي مسترجع", + "maxTokensGlobalContext": "أقصى عدد من الرموز للسياق العالمي", + "maxTokensGlobalContextTooltip": "الحد الأقصى لعدد الرموز المخصص لأوصاف العلاقات في الاسترجاع العالمي", + "maxTokensLocalContext": "أقصى عدد من الرموز للسياق المحلي", + "maxTokensLocalContextTooltip": "الحد الأقصى لعدد الرموز المخصص لأوصاف الكيانات في الاسترجاع المحلي", + "historyTurns": "دورات التاريخ", + "historyTurnsTooltip": "عدد الدورات الكاملة للمحادثة (أزواج المستخدم-المساعد) التي يجب مراعاتها في سياق الرد", + "historyTurnsPlaceholder": "عدد دورات التاريخ", + "hlKeywords": "الكلمات المفتاحية عالية المستوى", + "hlKeywordsTooltip": "قائمة الكلمات المفتاحية عالية المستوى لإعطائها الأولوية في الاسترجاع. افصل بينها بفواصل", + "hlkeywordsPlaceHolder": "أدخل الكلمات المفتاحية", + "llKeywords": "الكلمات المفتاحية منخفضة المستوى", + "llKeywordsTooltip": "قائمة الكلمات المفتاحية منخفضة المستوى لتحسين تركيز الاسترجاع. افصل بينها بفواصل", + "onlyNeedContext": "تحتاج فقط إلى السياق", + "onlyNeedContextTooltip": "إذا كان صحيحًا، يتم إرجاع السياق المسترجع فقط دون إنشاء رد", + "onlyNeedPrompt": "تحتاج فقط إلى المطالبة", + "onlyNeedPromptTooltip": "إذا كان صحيحًا، يتم إرجاع المطالبة المولدة فقط دون إنتاج رد", + "streamResponse": "تدفق الرد", + "streamResponseTooltip": "إذا كان صحيحًا، يتيح إخراج التدفق للردود في الوقت الفعلي" + } + }, + "apiSite": { + "loading": "جارٍ تحميل وثائق واجهة برمجة التطبيقات..." + } +} From 9021bfb8a6917da742fb62e13152d3b16eeee0cb Mon Sep 17 00:00:00 2001 From: Saifeddine ALOUI Date: Mon, 17 Mar 2025 18:57:48 +0100 Subject: [PATCH 3/3] Added french locale --- lightrag_webui/src/locales/fr.json | 239 +++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 lightrag_webui/src/locales/fr.json diff --git a/lightrag_webui/src/locales/fr.json b/lightrag_webui/src/locales/fr.json new file mode 100644 index 00000000..5de47e50 --- /dev/null +++ b/lightrag_webui/src/locales/fr.json @@ -0,0 +1,239 @@ +{ + "settings": { + "language": "Langue", + "theme": "Thème", + "light": "Clair", + "dark": "Sombre", + "system": "Système" + }, + "header": { + "documents": "Documents", + "knowledgeGraph": "Graphe de connaissances", + "retrieval": "Récupération", + "api": "API", + "projectRepository": "Référentiel du projet", + "themeToggle": { + "switchToLight": "Passer au thème clair", + "switchToDark": "Passer au thème sombre" + } + }, + "documentPanel": { + "clearDocuments": { + "button": "Effacer", + "tooltip": "Effacer les documents", + "title": "Effacer les documents", + "confirm": "Voulez-vous vraiment effacer tous les documents ?", + "confirmButton": "OUI", + "success": "Documents effacés avec succès", + "failed": "Échec de l'effacement des documents :\n{{message}}", + "error": "Échec de l'effacement des documents :\n{{error}}" + }, + "uploadDocuments": { + "button": "Télécharger", + "tooltip": "Télécharger des documents", + "title": "Télécharger des documents", + "description": "Glissez-déposez vos documents ici ou cliquez pour parcourir.", + "uploading": "Téléchargement de {{name}} : {{percent}}%", + "success": "Succès du téléchargement :\n{{name}} téléchargé avec succès", + "failed": "Échec du téléchargement :\n{{name}}\n{{message}}", + "error": "Échec du téléchargement :\n{{name}}\n{{error}}", + "generalError": "Échec du téléchargement\n{{error}}", + "fileTypes": "Types pris en charge : TXT, MD, DOCX, PDF, PPTX, RTF, ODT, EPUB, HTML, HTM, TEX, JSON, XML, YAML, YML, CSV, LOG, CONF, INI, PROPERTIES, SQL, BAT, SH, C, CPP, PY, JAVA, JS, TS, SWIFT, GO, RB, PHP, CSS, SCSS, LESS" + }, + "documentManager": { + "title": "Gestion des documents", + "scanButton": "Scanner", + "scanTooltip": "Scanner les documents", + "uploadedTitle": "Documents téléchargés", + "uploadedDescription": "Liste des documents téléchargés et leurs statuts.", + "emptyTitle": "Aucun document", + "emptyDescription": "Il n'y a pas encore de documents téléchargés.", + "columns": { + "id": "ID", + "summary": "Résumé", + "status": "Statut", + "length": "Longueur", + "chunks": "Fragments", + "created": "Créé", + "updated": "Mis à jour", + "metadata": "Métadonnées" + }, + "status": { + "completed": "Terminé", + "processing": "En traitement", + "pending": "En attente", + "failed": "Échoué" + }, + "errors": { + "loadFailed": "Échec du chargement des documents\n{{error}}", + "scanFailed": "Échec de la numérisation des documents\n{{error}}", + "scanProgressFailed": "Échec de l'obtention de la progression de la numérisation\n{{error}}" + } + } + }, + "graphPanel": { + "sideBar": { + "settings": { + "settings": "Paramètres", + "healthCheck": "Vérification de l'état", + "showPropertyPanel": "Afficher le panneau des propriétés", + "showSearchBar": "Afficher la barre de recherche", + "showNodeLabel": "Afficher l'étiquette du nœud", + "nodeDraggable": "Nœud déplaçable", + "showEdgeLabel": "Afficher l'étiquette de l'arête", + "hideUnselectedEdges": "Masquer les arêtes non sélectionnées", + "edgeEvents": "Événements des arêtes", + "maxQueryDepth": "Profondeur maximale de la requête", + "minDegree": "Degré minimum", + "maxLayoutIterations": "Itérations maximales de mise en page", + "depth": "Profondeur", + "degree": "Degré", + "apiKey": "Clé API", + "enterYourAPIkey": "Entrez votre clé API", + "save": "Sauvegarder", + "refreshLayout": "Actualiser la mise en page" + }, + "zoomControl": { + "zoomIn": "Zoom avant", + "zoomOut": "Zoom arrière", + "resetZoom": "Réinitialiser le zoom" + }, + "layoutsControl": { + "startAnimation": "Démarrer l'animation de mise en page", + "stopAnimation": "Arrêter l'animation de mise en page", + "layoutGraph": "Mettre en page le graphe", + "layouts": { + "Circular": "Circulaire", + "Circlepack": "Paquet circulaire", + "Random": "Aléatoire", + "Noverlaps": "Sans chevauchement", + "Force Directed": "Dirigé par la force", + "Force Atlas": "Atlas de force" + } + }, + "fullScreenControl": { + "fullScreen": "Plein écran", + "windowed": "Fenêtré" + } + }, + "statusIndicator": { + "connected": "Connecté", + "disconnected": "Déconnecté" + }, + "statusCard": { + "unavailable": "Informations sur l'état indisponibles", + "storageInfo": "Informations de stockage", + "workingDirectory": "Répertoire de travail", + "inputDirectory": "Répertoire d'entrée", + "llmConfig": "Configuration du modèle de langage", + "llmBinding": "Liaison du modèle de langage", + "llmBindingHost": "Hôte de liaison du modèle de langage", + "llmModel": "Modèle de langage", + "maxTokens": "Nombre maximum de jetons", + "embeddingConfig": "Configuration d'incorporation", + "embeddingBinding": "Liaison d'incorporation", + "embeddingBindingHost": "Hôte de liaison d'incorporation", + "embeddingModel": "Modèle d'incorporation", + "storageConfig": "Configuration de stockage", + "kvStorage": "Stockage clé-valeur", + "docStatusStorage": "Stockage de l'état des documents", + "graphStorage": "Stockage du graphe", + "vectorStorage": "Stockage vectoriel" + }, + "propertiesView": { + "node": { + "title": "Nœud", + "id": "ID", + "labels": "Étiquettes", + "degree": "Degré", + "properties": "Propriétés", + "relationships": "Relations", + "propertyNames": { + "description": "Description", + "entity_id": "Nom", + "entity_type": "Type", + "source_id": "ID source", + "Neighbour": "Voisin" + } + }, + "edge": { + "title": "Relation", + "id": "ID", + "type": "Type", + "source": "Source", + "target": "Cible", + "properties": "Propriétés" + } + }, + "search": { + "placeholder": "Rechercher des nœuds...", + "message": "Et {{count}} autres" + }, + "graphLabels": { + "selectTooltip": "Sélectionner l'étiquette de la requête", + "noLabels": "Aucune étiquette trouvée", + "label": "Étiquette", + "placeholder": "Rechercher des étiquettes...", + "andOthers": "Et {{count}} autres" + } + }, + "retrievePanel": { + "chatMessage": { + "copyTooltip": "Copier dans le presse-papiers", + "copyError": "Échec de la copie du texte dans le presse-papiers" + }, + "retrieval": { + "startPrompt": "Démarrez une récupération en tapant votre requête ci-dessous", + "clear": "Effacer", + "send": "Envoyer", + "placeholder": "Tapez votre requête...", + "error": "Erreur : Échec de l'obtention de la réponse" + }, + "querySettings": { + "parametersTitle": "Paramètres", + "parametersDescription": "Configurez vos paramètres de requête", + "queryMode": "Mode de requête", + "queryModeTooltip": "Sélectionnez la stratégie de récupération :\n• Naïf : Recherche de base sans techniques avancées\n• Local : Récupération d'informations dépendante du contexte\n• Global : Utilise une base de connaissances globale\n• Hybride : Combine récupération locale et globale\n• Mixte : Intègre le graphe de connaissances avec la récupération vectorielle", + "queryModeOptions": { + "naive": "Naïf", + "local": "Local", + "global": "Global", + "hybrid": "Hybride", + "mix": "Mixte" + }, + "responseFormat": "Format de réponse", + "responseFormatTooltip": "Définit le format de la réponse. Exemples :\n• Plusieurs paragraphes\n• Paragraphe unique\n• Points à puces", + "responseFormatOptions": { + "multipleParagraphs": "Plusieurs paragraphes", + "singleParagraph": "Paragraphe unique", + "bulletPoints": "Points à puces" + }, + "topK": "Top K résultats", + "topKTooltip": "Nombre d'éléments supérieurs à récupérer. Représente les entités en mode 'local' et les relations en mode 'global'", + "topKPlaceholder": "Nombre de résultats", + "maxTokensTextUnit": "Nombre maximum de jetons pour l'unité de texte", + "maxTokensTextUnitTooltip": "Nombre maximum de jetons autorisés pour chaque fragment de texte récupéré", + "maxTokensGlobalContext": "Nombre maximum de jetons pour le contexte global", + "maxTokensGlobalContextTooltip": "Nombre maximum de jetons alloués pour les descriptions des relations dans la récupération globale", + "maxTokensLocalContext": "Nombre maximum de jetons pour le contexte local", + "maxTokensLocalContextTooltip": "Nombre maximum de jetons alloués pour les descriptions des entités dans la récupération locale", + "historyTurns": "Tours d'historique", + "historyTurnsTooltip": "Nombre de tours complets de conversation (paires utilisateur-assistant) à prendre en compte dans le contexte de la réponse", + "historyTurnsPlaceholder": "Nombre de tours d'historique", + "hlKeywords": "Mots-clés de haut niveau", + "hlKeywordsTooltip": "Liste de mots-clés de haut niveau à prioriser dans la récupération. Séparez par des virgules", + "hlkeywordsPlaceHolder": "Entrez les mots-clés", + "llKeywords": "Mots-clés de bas niveau", + "llKeywordsTooltip": "Liste de mots-clés de bas niveau pour affiner la focalisation de la récupération. Séparez par des virgules", + "onlyNeedContext": "Besoin uniquement du contexte", + "onlyNeedContextTooltip": "Si vrai, ne renvoie que le contexte récupéré sans générer de réponse", + "onlyNeedPrompt": "Besoin uniquement de l'invite", + "onlyNeedPromptTooltip": "Si vrai, ne renvoie que l'invite générée sans produire de réponse", + "streamResponse": "Réponse en flux", + "streamResponseTooltip": "Si vrai, active la sortie en flux pour des réponses en temps réel" + } + }, + "apiSite": { + "loading": "Chargement de la documentation de l'API..." + } +}