Merge pull request #1591 from ManishMadan2882/main

Sync locales
This commit is contained in:
Alex
2025-01-18 22:30:18 +00:00
committed by GitHub
19 changed files with 687 additions and 284 deletions

View File

@@ -1,4 +1,5 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import SingleArrowLeft from '../assets/single-left-arrow.svg';
import SingleArrowRight from '../assets/single-right-arrow.svg';
import DoubleArrowLeft from '../assets/double-arrow-left.svg';
@@ -19,6 +20,7 @@ const Pagination: React.FC<PaginationProps> = ({
onPageChange,
onRowsPerPageChange,
}) => {
const { t } = useTranslation();
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const rowsPerPageOptions = [5, 10, 20, 50];
@@ -53,7 +55,9 @@ const Pagination: React.FC<PaginationProps> = ({
<div className="flex items-center text-xs justify-end gap-4 mt-2 p-2 border-gray-200">
{/* Rows per page dropdown */}
<div className="flex items-center gap-2 relative">
<span className="text-gray-900 dark:text-gray-50">Rows per page:</span>
<span className="text-gray-900 dark:text-gray-50">
{t('pagination.rowsPerPage')}:
</span>
<div className="relative">
<button
onClick={toggleDropdown}
@@ -87,7 +91,7 @@ const Pagination: React.FC<PaginationProps> = ({
{/* Pagination controls */}
<div className="text-gray-900 dark:text-gray-50">
Page {currentPage} of {totalPages}
{t('pagination.pageOf', { currentPage, totalPages })}
</div>
<div className="flex items-center gap-2 text-gray-900 dark:text-gray-50">
<button
@@ -97,7 +101,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={DoubleArrowLeft}
alt="First page"
alt={t('pagination.firstPage')}
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>
@@ -108,7 +112,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={SingleArrowLeft}
alt="Previous page"
alt={t('pagination.previousPage')}
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>
@@ -119,7 +123,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={SingleArrowRight}
alt="Next page"
alt={t('pagination.nextPage')}
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>
@@ -130,7 +134,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={DoubleArrowRight}
alt="Last page"
alt={t('pagination.lastPage')}
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>

View File

@@ -130,13 +130,13 @@ const ConversationBubble = forwardRef<
className="rounded-full bg-[#CDB5FF] hover:bg-[#E1D3FF] py-[10px] px-[15px] text-purple-30 max-w-full whitespace-pre-wrap leading-none"
onClick={() => handleEditClick()}
>
Update
{t('conversation.edit.update')}
</button>
<button
className="py-[10px] px-[15px] no-underline hover:underline text-purple-30 max-w-full whitespace-pre-wrap leading-normal"
onClick={() => setIsEditClicked(false)}
>
Cancel
{t('conversation.edit.cancel')}
</button>
</div>
</div>

View File

@@ -61,7 +61,6 @@
"noData": "No existing Documents",
"searchPlaceholder": "Search...",
"addNew": "Add New",
"addNewTitle": "Add New Document",
"preLoaded": "Pre-loaded",
"private": "Private",
"sync": "Sync",
@@ -82,24 +81,40 @@
"noData": "No existing Chatbots"
},
"analytics": {
"label": "Analytics"
"label": "Analytics",
"filterByChatbot": "Filter by chatbot",
"selectChatbot": "Select chatbot",
"filterOptions": {
"hour": "Hour",
"last24Hours": "24 Hours",
"last7Days": "7 Days",
"last15Days": "15 Days",
"last30Days": "30 Days"
},
"messages": "Messages",
"tokenUsage": "Token Usage",
"feedback": "Feedback",
"filterPlaceholder": "Filter",
"none": "None",
"positiveFeedback": "Positive Feedback",
"negativeFeedback": "Negative Feedback"
},
"logs": {
"label": "Logs",
"filterByChatbot": "Filter by chatbot",
"selectChatbot": "Select chatbot",
"none": "None",
"selectChatbotPlaceholder": "Select chatbot",
"apiGeneratedConversations": "API generated / chatbot conversations"
"tableHeader": "API generated / chatbot conversations"
},
"tools": {
"label": "Tools",
"searchPlaceholder": "Search tools...",
"addTool": "Add Tool",
"noToolsFound": "No tools found",
"selectToolSetup": "Select a tool to set up",
"settingsIconAlt": "Settings icon",
"configureToolAria": "Configure {toolName}",
"toggleToolAria": "Toggle {toolName}",
"selectToolSetup": "Select a tool to set up"
"toggleToolAria": "Toggle {toolName}"
}
},
"modals": {
@@ -125,11 +140,19 @@
"secret": "Client Secret",
"agent": "User agent",
"searchQueries": "Search queries",
"numberOfPosts": "Number of posts"
"numberOfPosts": "Number of posts",
"addQuery": "Add Query"
},
"drag": {
"title": "Upload a source file",
"description": "Drop your file here to add it as a source"
},
"progress": {
"upload": "Upload is in progress",
"training": "Training is in progress",
"completed": "Training completed",
"wait": "This may take several minutes",
"tokenLimit": "Over the token limit, please consider uploading smaller document"
}
},
"createAPIKey": {
@@ -156,6 +179,24 @@
"note": "Source document, personal information and further conversation will remain private",
"create": "Create",
"option": "Allow users to prompt further"
},
"configTool": {
"title": "Tool Config",
"type": "Type",
"apiKeyLabel": "API Key / OAuth",
"apiKeyPlaceholder": "Enter API Key / OAuth",
"addButton": "Add Tool",
"closeButton": "Close"
},
"prompts": {
"addPrompt": "Add Prompt",
"addDescription": "Add your custom prompt and save it to DocsGPT",
"editPrompt": "Edit Prompt",
"editDescription": "Edit your custom prompt and save it to DocsGPT",
"promptName": "Prompt Name",
"promptText": "Prompt Text",
"save": "Save",
"nameExists": "Name already exists"
}
},
"sharedConv": {
@@ -169,20 +210,28 @@
"rename": "Rename",
"deleteWarning": "Are you sure you want to delete this conversation?"
},
"pagination": {
"rowsPerPage": "Rows per page",
"pageOf": "Page {{currentPage}} of {{totalPages}}",
"firstPage": "First page",
"previousPage": "Previous page",
"nextPage": "Next page",
"lastPage": "Last page"
},
"conversation": {
"copy": "Copy",
"copied": "Copied",
"speak": "Speak",
"answer": "Answer",
"send": "Send message",
"loading": "Loading response",
"edit": {
"update": "Update",
"cancel": "Cancel",
"placeholder": "Type the updated query..."
},
"sources": {
"title": "Sources",
"text": "Source Text",
"link": "Source Link",
"text": "Source text",
"link": "Source link",
"view_more": "{{count}} more sources"
},
"retry": "Retry"

View File

@@ -61,7 +61,6 @@
"noData": "No hay documentos existentes",
"searchPlaceholder": "Buscar...",
"addNew": "Agregar Nuevo",
"addNewTitle": "Agregar Nuevo Documento",
"preLoaded": "Precargado",
"private": "Privado",
"sync": "Sincronizar",
@@ -70,7 +69,8 @@
"daily": "Diario",
"weekly": "Semanal",
"monthly": "Mensual"
}
},
"actions": "Acciones"
},
"apiKeys": {
"label": "Chatbots",
@@ -81,17 +81,40 @@
"noData": "No hay chatbots existentes"
},
"analytics": {
"label": "Analítica"
"label": "Analítica",
"filterByChatbot": "Filtrar por chatbot",
"selectChatbot": "Seleccionar chatbot",
"filterOptions": {
"hour": "Hora",
"last24Hours": "24 Horas",
"last7Days": "7 Días",
"last15Days": "15 Días",
"last30Days": "30 Días"
},
"messages": "Mensajes",
"tokenUsage": "Uso de Tokens",
"feedback": "Retroalimentación",
"filterPlaceholder": "Filtrar",
"none": "Ninguno",
"positiveFeedback": "Retroalimentación Positiva",
"negativeFeedback": "Retroalimentación Negativa"
},
"logs": {
"label": "Registros",
"filterByChatbot": "Filtrar por chatbot",
"selectChatbot": "Seleccionar chatbot",
"none": "Ninguno",
"selectChatbotPlaceholder": "Seleccionar chatbot",
"apiGeneratedConversations": "Conversaciones generadas por API / chatbot"
"tableHeader": "Conversaciones generadas por API / chatbot"
},
"tools": {
"label": "Herramientas"
"label": "Herramientas",
"searchPlaceholder": "Buscar...",
"addTool": "Agregar Herramienta",
"noToolsFound": "No se encontraron herramientas",
"selectToolSetup": "Seleccione una herramienta para configurar",
"settingsIconAlt": "Icono de configuración",
"configureToolAria": "Configurar {toolName}",
"toggleToolAria": "Alternar {toolName}"
}
},
"modals": {
@@ -113,15 +136,23 @@
"urlLink": "Enlace URL",
"repoUrl": "URL del Repositorio",
"reddit": {
"id": "ID de Cliente",
"secret": "Secreto de Cliente",
"agent": "Agente de Usuario",
"searchQueries": "Consultas de Búsqueda",
"numberOfPosts": "Número de publicaciones"
"id": "ID del Cliente",
"secret": "Secreto del Cliente",
"agent": "Agente de usuario",
"searchQueries": "Consultas de búsqueda",
"numberOfPosts": "Número de publicaciones",
"addQuery": "Agregar Consulta"
},
"drag": {
"title": "Carga un archivo fuente",
"description": "Suelta tu archivo aquí para añadirlo como fuente"
"title": "Subir archivo fuente",
"description": "Arrastra tu archivo aquí para agregarlo como fuente"
},
"progress": {
"upload": "Subida en progreso",
"training": "Entrenamiento en progreso",
"completed": "Entrenamiento completado",
"wait": "Esto puede tardar varios minutos",
"tokenLimit": "Excede el límite de tokens, considere cargar un documento más pequeño"
}
},
"createAPIKey": {
@@ -148,6 +179,24 @@
"note": "El documento fuente, información personal y conversaciones posteriores permanecerán privadas",
"create": "Crear",
"option": "Permitir a los usuarios realizar más consultas"
},
"configTool": {
"title": "Configuración de la Herramienta",
"type": "Tipo",
"apiKeyLabel": "Clave API / OAuth",
"apiKeyPlaceholder": "Ingrese la Clave API / OAuth",
"addButton": "Agregar Herramienta",
"closeButton": "Cerrar"
},
"prompts": {
"addPrompt": "Agregar Prompt",
"addDescription": "Agrega tu prompt personalizado y guárdalo en DocsGPT",
"editPrompt": "Editar Prompt",
"editDescription": "Edita tu prompt personalizado y guárdalo en DocsGPT",
"promptName": "Nombre del Prompt",
"promptText": "Texto del Prompt",
"save": "Guardar",
"nameExists": "El nombre ya existe"
}
},
"sharedConv": {
@@ -159,7 +208,15 @@
"share": "Compartir",
"delete": "Eliminar",
"rename": "Renombrar",
"deleteWarning": "¿Estás seguro de que deseas eliminar esta conversación?"
"deleteWarning": "¿Está seguro de que desea eliminar esta conversación?"
},
"pagination": {
"rowsPerPage": "Filas por página",
"pageOf": "Página {{currentPage}} de {{totalPages}}",
"firstPage": "Primera página",
"previousPage": "Página anterior",
"nextPage": "Página siguiente",
"lastPage": "Última página"
},
"conversation": {
"copy": "Copiar",
@@ -167,13 +224,15 @@
"speak": "Hablar",
"answer": "Respuesta",
"edit": {
"placeholder": "Escribe la consulta actualizada..."
"update": "Actualizar",
"cancel": "Cancelar",
"placeholder": "Ingrese la consulta actualizada..."
},
"sources": {
"title": "Fuentes",
"text": "Texto de la Fuente",
"link": "Enlace de la Fuente",
"view_more": "{{count}} más fuentes"
"text": "Texto fuente",
"link": "Enlace fuente",
"view_more": "Ver {{count}} más fuentes"
},
"retry": "Reintentar"
}

View File

@@ -1,7 +1,7 @@
{
"language": "日本語",
"chat": "チャット",
"chats": "チャット一覧",
"chats": "チャット",
"newChat": "新しいチャット",
"myPlan": "私のプラン",
"about": "について",
@@ -24,11 +24,11 @@
},
{
"header": "コードを書く",
"query": "APIリクエストのコードを/api/answerに書いてください"
"query": "APIリクエストのコードを/api/answerに書いてください"
},
{
"header": "学習支援",
"query": "コンテキストに対する潜在的な質問を書いてください"
"query": "このコンテンツに対する可能な質問を書いてください"
}
],
"settings": {
@@ -58,10 +58,9 @@
"date": "ベクトル日付",
"type": "タイプ",
"tokenUsage": "トークン使用量",
"noData": "既存のドキュメントありません",
"noData": "既存のドキュメントありません",
"searchPlaceholder": "検索...",
"addNew": "新規追加",
"addNewTitle": "新規ドキュメントを追加",
"preLoaded": "プリロード済み",
"private": "プライベート",
"sync": "同期",
@@ -69,29 +68,53 @@
"never": "なし",
"daily": "毎日",
"weekly": "毎週",
"monthly": "<EFBFBD><EFBFBD>月"
}
"monthly": "月"
},
"actions": "アクション"
},
"apiKeys": {
"label": "チャットボット",
"label": "APIキー",
"name": "名前",
"key": "APIキー",
"sourceDoc": "ソースドキュメント",
"createNew": "新規作成",
"noData": "既存のチャットボットはありません"
"noData": "既存のAPIキーがありません"
},
"analytics": {
"label": "分析"
"label": "分析",
"filterByChatbot": "チャットボットでフィルター",
"selectChatbot": "チャットボットを選択",
"filterOptions": {
"hour": "時間",
"last24Hours": "過去24時間",
"last7Days": "過去7日間",
"last15Days": "過去15日間",
"last30Days": "過去30日間"
},
"messages": "メッセージ",
"tokenUsage": "トークン使用量",
"feedback": "フィードバック",
"filterPlaceholder": "フィルター",
"none": "なし",
"positiveFeedback": "肯定的なフィードバック",
"negativeFeedback": "否定的なフィードバック"
},
"logs": {
"label": "ログ",
"filterByChatbot": "チャットボットでフィルタ",
"filterByChatbot": "チャットボットでフィルタ",
"selectChatbot": "チャットボットを選択",
"none": "なし",
"selectChatbotPlaceholder": "チャットボットを選択",
"apiGeneratedConversations": "API生成/チャットボット会話"
"tableHeader": "API生成 / チャットボットの会話"
},
"tools": {
"label": "ツール"
"label": "ツール",
"searchPlaceholder": "検索...",
"addTool": "ツールを追加",
"noToolsFound": "ツールが見つかりません",
"selectToolSetup": "設定するツールを選択してください",
"settingsIconAlt": "設定アイコン",
"configureToolAria": "{toolName} を設定",
"toggleToolAria": "{toolName} を切り替え"
}
},
"modals": {
@@ -105,7 +128,7 @@
"start": "チャットを開始する",
"name": "名前",
"choose": "ファイルを選択",
"info": ".pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zipファイルを25MBまでアップロードしてください",
"info": "25MBまでの.pdf.txt.rst.csv.xlsx.docx.md.html.epub.json.pptx.zipファイルをアップロードしてください",
"uploadedFiles": "アップロードされたファイル",
"cancel": "キャンセル",
"train": "トレーニング",
@@ -117,11 +140,19 @@
"secret": "クライアントシークレット",
"agent": "ユーザーエージェント",
"searchQueries": "検索クエリ",
"numberOfPosts": "投稿数"
"numberOfPosts": "投稿数",
"addQuery": "クエリを追加"
},
"drag": {
"title": "ソースファイルをアップロードする",
"description": "ファイルをここにドロップしてソースとして追加します"
"title": "ソースファイルをアップロード",
"description": "ファイルをここにドロップしてソースとして追加してください"
},
"progress": {
"upload": "アップロード中",
"training": "トレーニング中",
"completed": "トレーニング完了",
"wait": "数分かかる場合があります",
"tokenLimit": "トークン制限を超えています。より小さいドキュメントをアップロードしてください"
}
},
"createAPIKey": {
@@ -148,6 +179,24 @@
"note": "ソースドキュメント、個人情報、および以降の会話は非公開のままになります",
"create": "作成",
"option": "ユーザーがより多くのクエリを実行できるようにします。"
},
"configTool": {
"title": "ツール設定",
"type": "タイプ",
"apiKeyLabel": "APIキー / OAuth",
"apiKeyPlaceholder": "APIキー / OAuthを入力してください",
"addButton": "ツールを追加",
"closeButton": "閉じる"
},
"prompts": {
"addPrompt": "プロンプトを追加",
"addDescription": "カスタムプロンプトを追加してDocsGPTに保存",
"editPrompt": "プロンプトを編集",
"editDescription": "カスタムプロンプトを編集してDocsGPTに保存",
"promptName": "プロンプト名",
"promptText": "プロンプトテキスト",
"save": "保存",
"nameExists": "名前が既に存在します"
}
},
"sharedConv": {
@@ -161,19 +210,29 @@
"rename": "名前変更",
"deleteWarning": "この会話を削除してもよろしいですか?"
},
"pagination": {
"rowsPerPage": "1ページあたりの行数",
"pageOf": "ページ {{currentPage}} / {{totalPages}}",
"firstPage": "最初のページ",
"previousPage": "前のページ",
"nextPage": "次のページ",
"lastPage": "最後のページ"
},
"conversation": {
"copy": "コピー",
"copied": "コピーしました",
"speak": "スピーク",
"copied": "コピー済み",
"speak": "読み上げ",
"answer": "回答",
"edit": {
"placeholder": "更新されたクエリを入力してください..."
"update": "更新",
"cancel": "キャンセル",
"placeholder": "更新されたクエリを入力..."
},
"sources": {
"title": "ソース",
"text": "ソーステキスト",
"link": "ソースリンク",
"view_more": "さらに{{count}}個のソース"
"view_more": "さらに{{count}}個のソースを表示"
},
"retry": "再試行"
}

View File

@@ -4,7 +4,7 @@
"chats": "Чаты",
"newChat": "Новый чат",
"myPlan": "Мой план",
"about": "О",
"about": "О нас",
"inputPlaceholder": "Введите свое сообщение здесь...",
"tagline": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники.",
"sourceDocs": "Источник",
@@ -28,7 +28,7 @@
},
{
"header": "Помощь в обучении",
"query": "Написать потенциальные вопросы для контекста"
"query": "Написать возможные вопросы для этого контента"
}
],
"settings": {
@@ -37,7 +37,7 @@
"label": "Общие",
"selectTheme": "Выбрать тему",
"light": "Светлая",
"dark": "Темная",
"dark": "Тёмная",
"selectLanguage": "Выбрать язык",
"chunks": "Обработанные фрагменты на запрос",
"prompt": "Активная подсказка",
@@ -57,84 +57,115 @@
"name": "Название документа",
"date": "Дата вектора",
"type": "Тип",
"tokenUsage": "Использование токенов",
"tokenUsage": "Использование токена",
"noData": "Нет существующих документов",
"searchPlaceholder": "Поиск...",
"addNew": "Добавить новый",
"addNewTitle": "Добавить новый документ",
"addNew": "добавить новый",
"preLoaded": "Предзагруженный",
"private": "Личный",
"private": "Частный",
"sync": "Синхронизация",
"syncFrequency": {
"never": "Никогда",
"daily": "Ежедневно",
"weekly": "Еженедельно",
"monthly": "Ежемесячно"
}
},
"actions": "Действия"
},
"apiKeys": {
"label": "Чат-боты",
"label": "API ключи",
"name": "Название",
"key": "Ключ API",
"sourceDoc": "Исходный документ",
"key": "API ключ",
"sourceDoc": "Источник документа",
"createNew": "Создать новый",
"noData": "Нет существующих чат-ботов"
"noData": "Нет существующих API ключей"
},
"analytics": {
"label": "Аналитика"
"label": "Аналитика",
"filterByChatbot": "Фильтровать по чат-боту",
"selectChatbot": "Выбрать чат-бота",
"filterOptions": {
"hour": "Час",
"last24Hours": "Последние 24 часа",
"last7Days": "Последние 7 дней",
"last15Days": "Последние 15 дней",
"last30Days": "Последние 30 дней"
},
"messages": "Сообщения",
"tokenUsage": "Использование токена",
"feedback": "Обратная связь",
"filterPlaceholder": "Фильтр",
"none": "Нет",
"positiveFeedback": "Положительная обратная связь",
"negativeFeedback": "Отрицательная обратная связь"
},
"logs": {
"label": "Регистры",
"filterByChatbot": "Фильтр по чат-боту",
"label": "Журналы",
"filterByChatbot": "Фильтровать по чат-боту",
"selectChatbot": "Выбрать чат-бота",
"none": "Нет",
"selectChatbotPlaceholder": "Выберите чат-бота",
"apiGeneratedConversations": "Разговоры, сгенерированные API / чат-ботом"
"tableHeader": "API сгенерировано / разговоры с чат-ботом"
},
"tools": {
"label": "Инструменты"
"label": "Инструменты",
"searchPlaceholder": "Поиск...",
"addTool": "Добавить инструмент",
"noToolsFound": "Инструменты не найдены",
"selectToolSetup": "Выберите инструмент для настройки",
"settingsIconAlt": "Иконка настроек",
"configureToolAria": "Настроить {toolName}",
"toggleToolAria": "Переключить {toolName}"
}
},
"modals": {
"uploadDoc": {
"label": "Загрузить новую документацию",
"label": "Загрузить новый документ",
"select": "Выберите способ загрузки документа в DocsGPT",
"file": "Загрузить с устройства",
"back": "Назад",
"wait": "Пожалуйста, подождите ...",
"wait": "Пожалуйста, подождите...",
"remote": "Собрать с веб-сайта",
"start": "Начать чат",
"name": "Имя",
"choose": "Выбрать файлы",
"info": "Пожалуйста, загрузите .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip с ограничением до 25 МБ",
"info": "Пожалуйста, загрузите файлы .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip размером до 25 МБ",
"uploadedFiles": "Загруженные файлы",
"cancel": "Отмена",
"train": "Обучение",
"train": "Тренировка",
"link": "Ссылка",
"urlLink": "URL-ссылка",
"repoUrl": "URL-адрес репозитория",
"urlLink": "URL ссылка",
"repoUrl": "URL репозитория",
"reddit": {
"id": "ID клиента",
"secret": "Секрет клиента",
"agent": "Агент пользователя",
"agent": "Пользовательский агент",
"searchQueries": "Поисковые запросы",
"numberOfPosts": "Количество сообщений"
"numberOfPosts": "Количество сообщений",
"addQuery": "Добавить запрос"
},
"drag": {
"title": "Загрузите исходный файл",
"description": "Перетащите сюда свой файл, чтобы добавить его в качестве источника"
"title": "Загрузить исходный файл",
"description": "Перетащите файл сюда, чтобы добавить его как источник"
},
"progress": {
"upload": "Идет загрузка",
"training": "Идет обучение",
"completed": "Обучение завершено",
"wait": "Это может занять несколько минут",
"tokenLimit": "Превышен лимит токенов, рассмотрите возможность загрузки документа меньшего размера"
}
},
"createAPIKey": {
"label": "Создать новый ключ API",
"apiKeyName": "Имя ключа API",
"chunks": "Обработано фрагментов на запрос",
"label": "Создать новый API ключ",
"apiKeyName": "Название API ключа",
"chunks": "Обработанные фрагменты на запрос",
"prompt": "Выбрать активную подсказку",
"sourceDoc": "Исходный документ",
"sourceDoc": "Источник документа",
"create": "Создать"
},
"saveKey": {
"note": "Пожалуйста, сохраните свой ключ",
"disclaimer": "Это единственный раз, когда будет показан ваш ключ.",
"note": "Пожалуйста, сохраните ваш ключ",
"disclaimer": "Ваш ключ будет показан только один раз.",
"copy": "Копировать",
"copied": "Скопировано",
"confirm": "Я сохранил ключ"
@@ -144,16 +175,34 @@
"delete": "Удалить"
},
"shareConv": {
"label": "Создать публичную страницу для общего доступа",
"note": "Исходный документ, личная информация и дальнейший разговор останутся конфиденциальными",
"label": "Создать публичную страницу для совместного использования",
"note": "Исходный документ, личная информация и последующие разговоры останутся приватными",
"create": "Создать",
"option": "Разрешить пользователям продолжить диалог"
"option": "Позволить пользователям делать дополнительные запросы."
},
"configTool": {
"title": "Настройка инструмента",
"type": "Тип",
"apiKeyLabel": "API ключ / OAuth",
"apiKeyPlaceholder": "Введите API ключ / OAuth",
"addButton": "Добавить инструмент",
"closeButton": "Закрыть"
},
"prompts": {
"addPrompt": "Добавить подсказку",
"addDescription": "Добавить вашу пользовательскую подсказку и сохранить её в DocsGPT",
"editPrompt": "Редактировать подсказку",
"editDescription": "Редактировать вашу пользовательскую подсказку и сохранить её в DocsGPT",
"promptName": "Название подсказки",
"promptText": "Текст подсказки",
"save": "Сохранить",
"nameExists": "Название уже существует"
}
},
"sharedConv": {
"subtitle": "Создано с помощью",
"button": "Начать работу с DocsGPT",
"meta": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию с помощью источников."
"meta": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники."
},
"convTile": {
"share": "Поделиться",
@@ -161,19 +210,29 @@
"rename": "Переименовать",
"deleteWarning": "Вы уверены, что хотите удалить этот разговор?"
},
"pagination": {
"rowsPerPage": "Строк на странице",
"pageOf": "Страница {{currentPage}} из {{totalPages}}",
"firstPage": "Первая страница",
"previousPage": "Предыдущая страница",
"nextPage": "Следующая страница",
"lastPage": "Последняя страница"
},
"conversation": {
"copy": "Копировать",
"copied": "Скопировано",
"speak": "Говорить",
"speak": "Озвучить",
"answer": "Ответ",
"edit": {
"update": "Обновить",
"cancel": "Отмена",
"placeholder": "Введите обновленный запрос..."
},
"sources": {
"title": "Источники",
"text": "Исходный текст",
"link": "Исходная ссылка",
"view_more": "Еще {{count}} источников"
"text": "Текст источника",
"link": "Ссылка на источник",
"view_more": "Показать еще {{count}} источников"
},
"retry": "Повторить"
}

View File

@@ -10,8 +10,8 @@
"sourceDocs": "原始文件",
"none": "無",
"cancel": "取消",
"help": "聯繫支援",
"emailUs": "寄送電子郵件給我們",
"help": "幫助",
"emailUs": "給我們發電郵",
"documentation": "文件",
"demo": [
{
@@ -60,16 +60,17 @@
"tokenUsage": "Token 使用量",
"noData": "沒有現有的文件",
"searchPlaceholder": "搜尋...",
"addNewTitle": "新增文件",
"addNew": "新增文件",
"preLoaded": "預載入",
"private": "私人",
"sync": "同步",
"syncFrequency": {
"never": "不",
"daily": "每",
"never": "不",
"daily": "每",
"weekly": "每週",
"monthly": "每月"
}
},
"actions": "操作"
},
"apiKeys": {
"label": "聊天機器人",
@@ -80,17 +81,40 @@
"noData": "沒有現有的聊天機器人"
},
"analytics": {
"label": "分析"
"label": "分析",
"filterByChatbot": "按聊天機器人篩選",
"selectChatbot": "選擇聊天機器人",
"filterOptions": {
"hour": "小時",
"last24Hours": "24 小時",
"last7Days": "7 天",
"last15Days": "15 天",
"last30Days": "30 天"
},
"messages": "訊息",
"tokenUsage": "Token 使用量",
"feedback": "回饋",
"filterPlaceholder": "篩選",
"none": "無",
"positiveFeedback": "正向回饋",
"negativeFeedback": "負向回饋"
},
"logs": {
"label": "日誌",
"filterByChatbot": "按聊天機器人篩選",
"selectChatbot": "選擇聊天機器人",
"none": "無",
"selectChatbotPlaceholder": "選擇聊天機器人",
"apiGeneratedConversations": "API生成/聊天機器人對話"
"tableHeader": "API 生成 / 聊天機器人會話"
},
"tools": {
"label": "工具"
"label": "工具",
"searchPlaceholder": "搜尋...",
"addTool": "新增工具",
"noToolsFound": "找不到工具",
"selectToolSetup": "選擇要設定的工具",
"settingsIconAlt": "設定圖標",
"configureToolAria": "配置 {toolName}",
"toggleToolAria": "切換 {toolName}"
}
},
"modals": {
@@ -98,29 +122,37 @@
"label": "上傳新文件",
"select": "選擇如何將文件上傳到 DocsGPT",
"file": "從檔案",
"remote": "遠端",
"back": "返回",
"wait": "請稍候...",
"remote": "從網站收集",
"start": "開始對話",
"name": "名稱",
"choose": "選擇檔案",
"info": "請上傳 .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip 檔案,大小限制為 25MB",
"uploadedFiles": "已上傳檔案",
"info": "請上傳限制為25MB的.pdf.txt.rst.csv.xlsx.docx.md.html.epub.json.pptx.zip檔案",
"uploadedFiles": "已上傳檔案",
"cancel": "取消",
"train": "訓練",
"link": "連結",
"urlLink": "URL 連結",
"repoUrl": "儲存庫 URL",
"reddit": {
"id": "戶端 ID",
"secret": "戶端鑰",
"id": "戶端ID",
"secret": "戶端鑰",
"agent": "使用者代理",
"searchQueries": "搜尋查詢",
"numberOfPosts": "貼文數量"
"numberOfPosts": "貼文數量",
"addQuery": "新增查詢"
},
"drag": {
"title": "上傳原始檔",
"description": "將您的文件拖放到此處以將其添加為來源"
"title": "上傳來源檔案",
"description": "將檔案拖放到此處以新增為來源"
},
"progress": {
"upload": "正在上傳",
"training": "正在訓練",
"completed": "訓練完成",
"wait": "這可能需要幾分鐘",
"tokenLimit": "超出令牌限制,請考慮上傳較小的文檔"
}
},
"createAPIKey": {
@@ -146,7 +178,25 @@
"label": "建立公開頁面以分享",
"note": "來源文件、個人資訊和後續對話將保持私密",
"create": "建立",
"option": "允許用戶進行更多查詢"
"option": "允許使用者進行更多查詢"
},
"configTool": {
"title": "工具設定",
"type": "類型",
"apiKeyLabel": "API 金鑰 / OAuth",
"apiKeyPlaceholder": "輸入 API 金鑰 / OAuth",
"addButton": "新增工具",
"closeButton": "關閉"
},
"prompts": {
"addPrompt": "新增提示",
"addDescription": "新增自定義提示並儲存到 DocsGPT",
"editPrompt": "編輯提示",
"editDescription": "編輯自定義提示並儲存到 DocsGPT",
"promptName": "提示名稱",
"promptText": "提示文字",
"save": "儲存",
"nameExists": "名稱已存在"
}
},
"sharedConv": {
@@ -160,19 +210,29 @@
"rename": "重新命名",
"deleteWarning": "您確定要刪除這個對話嗎?"
},
"pagination": {
"rowsPerPage": "每頁行數",
"pageOf": "第 {{currentPage}} 頁,共 {{totalPages}} 頁",
"firstPage": "第一頁",
"previousPage": "上一頁",
"nextPage": "下一頁",
"lastPage": "最後一頁"
},
"conversation": {
"copy": "複製",
"copied": "已複製",
"speak": "朗讀",
"answer": "回答",
"edit": {
"update": "更新",
"cancel": "取消",
"placeholder": "輸入更新的查詢..."
},
"sources": {
"title": "來源",
"text": "來源文字",
"link": "來源連結",
"view_more": "更多{{count}}個來源"
"view_more": "查看更多 {{count}} 個來源"
},
"retry": "重試"
}

View File

@@ -10,7 +10,7 @@
"sourceDocs": "源",
"none": "无",
"cancel": "取消",
"help": "联系支持",
"help": "帮助",
"emailUs": "给我们发邮件",
"documentation": "文档",
"demo": [
@@ -60,7 +60,7 @@
"tokenUsage": "令牌使用",
"noData": "没有现有的文档",
"searchPlaceholder": "搜索...",
"addNewTitle": "添加新文档",
"addNew": "添加新文档",
"preLoaded": "预加载",
"private": "私有",
"sync": "同步",
@@ -69,7 +69,8 @@
"daily": "每天",
"weekly": "每周",
"monthly": "每月"
}
},
"actions": "操作"
},
"apiKeys": {
"label": "聊天机器人",
@@ -80,17 +81,40 @@
"noData": "没有现有的聊天机器人"
},
"analytics": {
"label": "分析"
"label": "分析",
"filterByChatbot": "按聊天机器人筛选",
"selectChatbot": "选择聊天机器人",
"filterOptions": {
"hour": "小时",
"last24Hours": "24 小时",
"last7Days": "7 天",
"last15Days": "15 天",
"last30Days": "30 天"
},
"messages": "消息",
"tokenUsage": "令牌使用",
"feedback": "反馈",
"filterPlaceholder": "筛选",
"none": "无",
"positiveFeedback": "正向反馈",
"negativeFeedback": "负向反馈"
},
"logs": {
"label": "日志",
"filterByChatbot": "按聊天机器人筛选",
"selectChatbot": "选择聊天机器人",
"none": "无",
"selectChatbotPlaceholder": "选择聊天机器人",
"apiGeneratedConversations": "API生成/聊天机器人对话"
"tableHeader": "API 生成 / 聊天机器人会话"
},
"tools": {
"label": "工具"
"label": "工具",
"searchPlaceholder": "搜索...",
"addTool": "添加工具",
"noToolsFound": "未找到工具",
"selectToolSetup": "选择要设置的工具" ,
"settingsIconAlt": "设置图标",
"configureToolAria": "配置 {toolName}",
"toggleToolAria": "切换 {toolName}"
}
},
"modals": {
@@ -104,7 +128,7 @@
"start": "开始聊天",
"name": "名称",
"choose": "选择文件",
"info": "请上传 .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip 文件,限制为 25MB",
"info": "请上传限制为25MB的.pdf.txt.rst.csv.xlsx.docx.md.html.epub.json.pptx.zip文件",
"uploadedFiles": "已上传文件",
"cancel": "取消",
"train": "训练",
@@ -112,15 +136,23 @@
"urlLink": "URL 链接",
"repoUrl": "存储库 URL",
"reddit": {
"id": "客户端 ID",
"id": "客户端ID",
"secret": "客户端密钥",
"agent": "用户代理",
"searchQueries": "搜索查询",
"numberOfPosts": "帖子数量"
"numberOfPosts": "帖子数量",
"addQuery": "添加查询"
},
"drag": {
"title": "上传源文件",
"description": "将您的文件拖放到此处以将其添加为源"
"description": "将文件拖放到此处以添加为源"
},
"progress": {
"upload": "正在上传",
"training": "正在训练",
"completed": "训练完成",
"wait": "这可能需要几分钟",
"tokenLimit": "超出令牌限制,请考虑上传较小的文档"
}
},
"createAPIKey": {
@@ -146,7 +178,25 @@
"label": "创建用于分享的公共页面",
"note": "源文档、个人信息和后续对话将保持私密",
"create": "创建",
"option": "允许用户进行更多查询"
"option": "允许用户进行更多查询"
},
"configTool": {
"title": "工具配置",
"type": "类型",
"apiKeyLabel": "API 密钥 / OAuth",
"apiKeyPlaceholder": "输入 API 密钥 / OAuth",
"addButton": "添加工具",
"closeButton": "关闭"
},
"prompts": {
"addPrompt": "添加提示",
"addDescription": "添加自定义提示并保存到 DocsGPT",
"editPrompt": "编辑提示",
"editDescription": "编辑自定义提示并保存到 DocsGPT",
"promptName": "提示名称",
"promptText": "提示文本",
"save": "保存",
"nameExists": "名称已存在"
}
},
"sharedConv": {
@@ -160,12 +210,22 @@
"rename": "重命名",
"deleteWarning": "您确定要删除此对话吗?"
},
"pagination": {
"rowsPerPage": "每页行数",
"pageOf": "第 {{currentPage}} 页,共 {{totalPages}} 页",
"firstPage": "第一页",
"previousPage": "上一页",
"nextPage": "下一页",
"lastPage": "最后一页"
},
"conversation": {
"copy": "复制",
"copied": "已复制",
"speak": "朗读",
"answer": "回答",
"edit": {
"update": "更新",
"cancel": "取消",
"placeholder": "输入更新的查询..."
},
"sources": {

View File

@@ -1,10 +1,11 @@
import React from 'react';
import React, { useRef } from 'react';
import userService from '../api/services/userService';
import Exit from '../assets/exit.svg';
import { ActiveState } from '../models/misc';
import { AvailableTool } from './types';
import ConfigToolModal from './ConfigToolModal';
import { useOutsideAlerter } from '../hooks';
import { useTranslation } from 'react-i18next';
export default function AddToolModal({
message,
@@ -25,6 +26,14 @@ export default function AddToolModal({
);
const [configModalState, setConfigModalState] =
React.useState<ActiveState>('INACTIVE');
const modalRef = useRef<HTMLDivElement>(null);
const { t } = useTranslation();
useOutsideAlerter(modalRef, () => {
if (modalState === 'ACTIVE') {
setModalState('INACTIVE');
}
}, [modalState]);
const getAvailableTools = () => {
userService
@@ -63,14 +72,18 @@ export default function AddToolModal({
React.useEffect(() => {
if (modalState === 'ACTIVE') getAvailableTools();
}, [modalState]);
return (
<>
<div
className={`${
modalState === 'ACTIVE' ? 'visible' : 'hidden'
} fixed top-0 left-0 z-30 h-screen w-screen bg-gray-alpha flex items-center justify-center`}
} fixed top-0 left-0 z-30 h-screen w-screen bg-gray-alpha flex items-center justify-center`}
>
<article className="flex h-[85vh] w-[90vw] md:w-[75vw] flex-col gap-4 rounded-2xl bg-[#FBFBFB] shadow-lg dark:bg-[#26272E]">
<article
ref={modalRef}
className="flex h-[85vh] w-[90vw] md:w-[75vw] flex-col gap-4 rounded-2xl bg-[#FBFBFB] shadow-lg dark:bg-[#26272E]"
>
<div className="relative">
<button
className="absolute top-3 right-4 m-2 w-3"
@@ -78,11 +91,15 @@ export default function AddToolModal({
setModalState('INACTIVE');
}}
>
<img className="filter dark:invert" src={Exit} />
<img
className="filter dark:invert"
src={Exit}
alt={t('cancel')}
/>
</button>
<div className="p-6">
<h2 className="font-semibold text-xl text-jet dark:text-bright-gray px-3">
Select a tool to set up
{t('settings.tools.selectToolSetup')}
</h2>
<div className="mt-5 flex flex-col sm:grid sm:grid-cols-3 gap-4 h-[73vh] overflow-auto px-3 py-px">
{availableTools.map((tool, index) => (

View File

@@ -1,4 +1,5 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import Exit from '../assets/exit.svg';
import Input from '../components/Input';
@@ -17,6 +18,7 @@ export default function ConfigToolModal({
tool: AvailableTool | null;
getUserTools: () => void;
}) {
const { t } = useTranslation();
const [authKey, setAuthKey] = React.useState<string>('');
const handleAddTool = (tool: AvailableTool) => {
@@ -52,21 +54,22 @@ export default function ConfigToolModal({
</button>
<div className="p-6">
<h2 className="font-semibold text-xl text-jet dark:text-bright-gray px-3">
Tool Config
{t('modals.configTool.title')}
</h2>
<p className="mt-5 text-sm text-gray-600 dark:text-gray-400 px-3">
Type: <span className="font-semibold">{tool?.name} </span>
{t('modals.configTool.type')}:{' '}
<span className="font-semibold">{tool?.name} </span>
</p>
<div className="mt-6 relative px-3">
<span className="absolute left-5 -top-2 bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
API Key / Oauth
{t('modals.configTool.apiKeyLabel')}
</span>
<Input
type="text"
value={authKey}
onChange={(e) => setAuthKey(e.target.value)}
borderVariant="thin"
placeholder="Enter API Key / Oauth"
placeholder={t('modals.configTool.apiKeyPlaceholder')}
></Input>
</div>
<div className="mt-8 flex flex-row-reverse gap-1 px-3">
@@ -76,7 +79,7 @@ export default function ConfigToolModal({
}}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-[#6F3FD1]"
>
Add Tool
{t('modals.configTool.addButton')}
</button>
<button
onClick={() => {
@@ -84,7 +87,7 @@ export default function ConfigToolModal({
}}
className="cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:text-light-gray dark:hover:bg-[#767183]/50"
>
Close
{t('modals.configTool.closeButton')}
</button>
</div>
</div>

View File

@@ -101,11 +101,17 @@ export const ShareConversationModal = ({
return (
<WrapperModal close={close}>
<div className="flex flex-col gap-2">
<h2 className="text-xl font-medium">{t('modals.shareConv.label')}</h2>
<p className="text-sm">{t('modals.shareConv.note')}</p>
<h2 className="text-xl font-medium text-eerie-black dark:text-white">
{t('modals.shareConv.label')}
</h2>
<p className="text-sm text-eerie-black dark:text-white">
{t('modals.shareConv.note')}
</p>
<div className="flex items-center justify-between">
<span className="text-lg">{t('modals.shareConv.option')}</span>
<label className=" cursor-pointer select-none items-center">
<span className="text-lg text-eerie-black dark:text-white">
{t('modals.shareConv.option')}
</span>
<label className="cursor-pointer select-none items-center">
<div className="relative">
<input
type="checkbox"
@@ -143,7 +149,7 @@ export const ShareConversationModal = ({
</div>
)}
<div className="flex items-baseline justify-between gap-2">
<span className="no-scrollbar w-full overflow-x-auto whitespace-nowrap rounded-full border-2 py-3 px-4">
<span className="no-scrollbar w-full overflow-x-auto whitespace-nowrap rounded-full border-2 py-3 px-4 text-eerie-black dark:text-white">
{`${domain}/share/${identifier ?? '....'}`}
</span>
{status === 'fetched' ? (

View File

@@ -14,4 +14,5 @@ export type WrapperModalProps = {
children?: React.ReactNode;
isPerformingTask?: boolean;
close: () => void;
className?: string;
};

View File

@@ -2,6 +2,7 @@ import { ActiveState } from '../models/misc';
import Exit from '../assets/exit.svg';
import Input from '../components/Input';
import React from 'react';
import { useTranslation } from 'react-i18next';
function AddPrompt({
setModalState,
@@ -20,6 +21,8 @@ function AddPrompt({
setNewPromptContent: (content: string) => void;
disableSave: boolean;
}) {
const { t } = useTranslation();
return (
<div className="relative">
<button
@@ -35,18 +38,17 @@ function AddPrompt({
</button>
<div className="p-8">
<p className="mb-1 text-xl text-jet dark:text-bright-gray">
Add Prompt
{t('modals.prompts.addPrompt')}
</p>
<p className="mb-7 text-xs text-[#747474] dark:text-[#7F7F82]">
Add your custom prompt and save it to DocsGPT
{t('modals.prompts.addDescription')}
</p>
<div>
<label htmlFor="new-prompt-name" className="sr-only">
Prompt Name
</label>
<Input
id="new-prompt-name"
placeholder="Prompt Name"
placeholder={t('modals.prompts.promptName')}
type="text"
className="h-10 rounded-lg"
value={newPromptName}
@@ -54,12 +56,12 @@ function AddPrompt({
/>
<div className="relative bottom-12 left-3 mt-[-3.00px]">
<span className="bg-white px-1 text-xs text-silver dark:bg-outer-space dark:text-silver">
Prompt Name
{t('modals.prompts.promptName')}
</span>
</div>
<div className="relative top-[7px] left-3">
<span className="bg-white px-1 text-xs text-silver dark:bg-outer-space dark:text-silver">
Prompt Text
{t('modals.prompts.promptText')}
</span>
</div>
<label htmlFor="new-prompt-content" className="sr-only">
@@ -78,9 +80,11 @@ function AddPrompt({
onClick={handleAddPrompt}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:opacity-90"
disabled={disableSave}
title={disableSave && newPromptName ? 'Name already exists' : ''}
title={
disableSave && newPromptName ? t('modals.prompts.nameExists') : ''
}
>
Save
{t('modals.prompts.save')}
</button>
</div>
</div>
@@ -107,6 +111,8 @@ function EditPrompt({
currentPromptEdit: { name: string; id: string; type: string };
disableSave: boolean;
}) {
const { t } = useTranslation();
return (
<div className="relative">
<button
@@ -120,18 +126,17 @@ function EditPrompt({
</button>
<div className="p-8">
<p className="mb-1 text-xl text-jet dark:text-bright-gray">
Edit Prompt
{t('modals.prompts.editPrompt')}
</p>
<p className="mb-7 text-xs text-[#747474] dark:text-[#7F7F82]">
Edit your custom prompt and save it to DocsGPT
{t('modals.prompts.editDescription')}
</p>
<div>
<label htmlFor="edit-prompt-name" className="sr-only">
Prompt Name
</label>
<Input
id="edit-prompt-name"
placeholder="Prompt Name"
placeholder={t('modals.prompts.promptName')}
type="text"
className="h-10 rounded-lg"
value={editPromptName}
@@ -139,12 +144,12 @@ function EditPrompt({
/>
<div className="relative bottom-12 left-3 mt-[-3.00px]">
<span className="bg-white px-1 text-xs text-silver dark:bg-outer-space dark:text-silver">
Prompt Name
{t('modals.prompts.promptName')}
</span>
</div>
<div className="relative top-[7px] left-3">
<span className="bg-white px-1 text-xs text-silver dark:bg-outer-space dark:text-silver">
Prompt Text
{t('modals.prompts.promptText')}
</span>
</div>
<label htmlFor="edit-prompt-content" className="sr-only">
@@ -170,9 +175,13 @@ function EditPrompt({
handleEditPrompt(currentPromptEdit.id, currentPromptEdit.type);
}}
disabled={currentPromptEdit.type === 'public' || disableSave}
title={disableSave && editPromptName ? 'Name already exists' : ''}
title={
disableSave && editPromptName
? t('modals.prompts.nameExists')
: ''
}
>
Save
{t('modals.prompts.save')}
</button>
</div>
</div>

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import {
BarElement,
CategoryScale,
@@ -28,15 +29,29 @@ ChartJS.register(
Legend,
);
const filterOptions = [
{ label: 'Hour', value: 'last_hour' },
{ label: '24 Hours', value: 'last_24_hour' },
{ label: '7 Days', value: 'last_7_days' },
{ label: '15 Days', value: 'last_15_days' },
{ label: '30 Days', value: 'last_30_days' },
];
export default function Analytics() {
const { t } = useTranslation();
const filterOptions = [
{ label: t('settings.analytics.filterOptions.hour'), value: 'last_hour' },
{
label: t('settings.analytics.filterOptions.last24Hours'),
value: 'last_24_hour',
},
{
label: t('settings.analytics.filterOptions.last7Days'),
value: 'last_7_days',
},
{
label: t('settings.analytics.filterOptions.last15Days'),
value: 'last_15_days',
},
{
label: t('settings.analytics.filterOptions.last30Days'),
value: 'last_30_days',
},
];
const [messagesData, setMessagesData] = useState<Record<
string,
number
@@ -54,15 +69,24 @@ export default function Analytics() {
const [messagesFilter, setMessagesFilter] = useState<{
label: string;
value: string;
}>({ label: '30 Days', value: 'last_30_days' });
}>({
label: t('settings.analytics.filterOptions.last30Days'),
value: 'last_30_days',
});
const [tokenUsageFilter, setTokenUsageFilter] = useState<{
label: string;
value: string;
}>({ label: '30 Days', value: 'last_30_days' });
}>({
label: t('settings.analytics.filterOptions.last30Days'),
value: 'last_30_days',
});
const [feedbackFilter, setFeedbackFilter] = useState<{
label: string;
value: string;
}>({ label: '30 Days', value: 'last_30_days' });
}>({
label: t('settings.analytics.filterOptions.last30Days'),
value: 'last_30_days',
});
const [loadingMessages, setLoadingMessages] = useState(true);
const [loadingTokens, setLoadingTokens] = useState(true);
@@ -164,8 +188,8 @@ export default function Analytics() {
<div className="mt-12">
<div className="flex flex-col items-start">
<div className="flex flex-col gap-3">
<p className="font-bold text-gray-800 dark:text-bright-gray">
Filter by chatbot
<p className="font-bold text-jet dark:text-bright-gray">
{t('settings.analytics.filterByChatbot')}
</p>
<Dropdown
size="w-[55vw] sm:w-[360px]"
@@ -174,9 +198,9 @@ export default function Analytics() {
label: chatbot.name,
value: chatbot.id,
})),
{ label: 'None', value: '' },
{ label: t('settings.analytics.none'), value: '' },
]}
placeholder="Select chatbot"
placeholder={t('settings.analytics.selectChatbot')}
onSelect={(chatbot: { label: string; value: string }) => {
setSelectedChatbot(
chatbots.find((item) => item.id === chatbot.value),
@@ -200,12 +224,12 @@ export default function Analytics() {
<div className="h-[345px] [@media(min-width:1080px)]:w-1/2 w-full px-6 py-5 border rounded-2xl border-silver dark:border-silver/40 overflow-hidden">
<div className="flex flex-row items-center justify-start gap-3">
<p className="font-bold text-jet dark:text-bright-gray">
Messages
{t('settings.analytics.messages')}
</p>
<Dropdown
size="w-[125px]"
options={filterOptions}
placeholder="Filter"
placeholder={t('settings.analytics.filterPlaceholder')}
onSelect={(selectedOption: {
label: string;
value: string;
@@ -233,7 +257,7 @@ export default function Analytics() {
),
datasets: [
{
label: 'Messages',
label: t('settings.analytics.messages'),
data: Object.values(messagesData || {}),
backgroundColor: '#7D54D1',
},
@@ -251,12 +275,12 @@ export default function Analytics() {
<div className="h-[345px] [@media(min-width:1080px)]:w-1/2 w-full px-6 py-5 border rounded-2xl border-silver dark:border-silver/40 overflow-hidden">
<div className="flex flex-row items-center justify-start gap-3">
<p className="font-bold text-jet dark:text-bright-gray">
Token Usage
{t('settings.analytics.tokenUsage')}
</p>
<Dropdown
size="w-[125px]"
options={filterOptions}
placeholder="Filter"
placeholder={t('settings.analytics.filterPlaceholder')}
onSelect={(selectedOption: {
label: string;
value: string;
@@ -284,7 +308,7 @@ export default function Analytics() {
),
datasets: [
{
label: 'Tokens',
label: t('settings.analytics.tokenUsage'),
data: Object.values(tokenUsageData || {}),
backgroundColor: '#7D54D1',
},
@@ -304,12 +328,12 @@ export default function Analytics() {
<div className="h-[345px] w-full px-6 py-5 border rounded-2xl border-silver dark:border-silver/40 overflow-hidden">
<div className="flex flex-row items-center justify-start gap-3">
<p className="font-bold text-jet dark:text-bright-gray">
Feedback
{t('settings.analytics.feedback')}
</p>
<Dropdown
size="w-[125px]"
options={filterOptions}
placeholder="Filter"
placeholder={t('settings.analytics.filterPlaceholder')}
onSelect={(selectedOption: {
label: string;
value: string;
@@ -337,14 +361,14 @@ export default function Analytics() {
),
datasets: [
{
label: 'Positive Feedback',
label: t('settings.analytics.positiveFeedback'),
data: Object.values(feedbackData || {}).map(
(item) => item.positive,
),
backgroundColor: '#7D54D1',
},
{
label: 'Negative Feedback',
label: t('settings.analytics.negativeFeedback'),
data: Object.values(feedbackData || {}).map(
(item) => item.negative,
),

View File

@@ -169,10 +169,10 @@ const Documents: React.FC<DocumentsProps> = ({
</div>
<button
className="rounded-full w-40 bg-purple-30 px-4 py-3 text-white hover:bg-[#6F3FD1]"
title={t('settings.documents.addNewTitle')}
title={t('settings.documents.addNew')}
onClick={() => {
setIsOnboarding(false); // Set onboarding flag if needed
setModalState('ACTIVE'); // Open the upload modal
setIsOnboarding(false);
setModalState('ACTIVE');
}}
>
{t('settings.documents.addNew')}
@@ -224,7 +224,7 @@ const Documents: React.FC<DocumentsProps> = ({
*/}
<th
scope="col"
className="px-6 py-2 text-start font-medium text-gray-700 dark:text-gray-50 uppercase"
className="px-6 py-2 text-start font-medium text-gray-700 dark:text-gray-50 uppercase sr-only"
aria-label={t('settings.documents.actions')}
>
{t('settings.documents.actions')}

View File

@@ -19,9 +19,12 @@ import Prompts from './Prompts';
export default function General() {
const {
t,
i18n: { changeLanguage, language },
i18n: { changeLanguage },
} = useTranslation();
const themes = [t('settings.general.light'), t('settings.general.dark')];
const themes = [
{ value: 'Light', label: t('settings.general.light') },
{ value: 'Dark', label: t('settings.general.dark') },
];
const languageOptions = [
{ label: 'English', value: 'en' },
@@ -86,10 +89,12 @@ export default function General() {
</label>
<Dropdown
options={themes}
selectedValue={selectedTheme}
onSelect={(option: string) => {
setSelectedTheme(option);
option !== selectedTheme && toggleTheme();
selectedValue={
themes.find((theme) => theme.value === selectedTheme) || null
}
onSelect={(option: { value: string; label: string }) => {
setSelectedTheme(option.value);
option.value !== selectedTheme && toggleTheme();
}}
size="w-56"
rounded="3xl"

View File

@@ -85,7 +85,7 @@ export default function Logs() {
})),
{ label: t('settings.logs.none'), value: '' },
]}
placeholder={t('settings.logs.selectChatbotPlaceholder')}
placeholder={t('settings.logs.selectChatbot')}
onSelect={(chatbot: { label: string; value: string }) => {
setSelectedChatbot(
chatbots.find((item) => item.id === chatbot.value),
@@ -140,7 +140,7 @@ function LogsTable({ logs, setPage }: LogsTableProps) {
<div className="logs-table border rounded-2xl h-[55vh] w-full overflow-hidden border-silver dark:border-silver/40">
<div className="h-8 bg-black/10 dark:bg-chinese-black flex flex-col items-start justify-center">
<p className="px-3 text-xs dark:text-gray-6000">
{t('settings.logs.apiGeneratedConversations')}
{t('settings.logs.tableHeader')}
</p>
</div>
<div
@@ -174,7 +174,7 @@ function Log({ log }: { log: LogData }) {
<summary className="flex flex-row items-center gap-2 text-gray-900 cursor-pointer p-2 group-open:bg-[#F9F9F9] dark:group-open:bg-dark-charcoal">
<img
src={ChevronRight}
alt="chevron-right"
alt="Expand log entry"
className="w-3 h-3 transition duration-300 group-open:rotate-90"
/>
<span className="flex flex-row gap-2">

View File

@@ -13,13 +13,13 @@ import ToolConfig from './ToolConfig';
import { UserTool } from './types';
export default function Tools() {
const { t } = useTranslation();
const [isDarkTheme] = useDarkTheme();
const [searchTerm, setSearchTerm] = React.useState('');
const [addToolModalState, setAddToolModalState] =
React.useState<ActiveState>('INACTIVE');
const [userTools, setUserTools] = React.useState<UserTool[]>([]);
const [selectedTool, setSelectedTool] = React.useState<UserTool | null>(null);
const { t } = useTranslation();
const getUserTools = () => {
userService
@@ -78,7 +78,7 @@ export default function Tools() {
<Input
maxLength={256}
placeholder={t('settings.tools.searchPlaceholder')}
name="tool-search-input"
name="Document-search-input"
type="text"
id="tool-search-input"
value={searchTerm}
@@ -86,7 +86,7 @@ export default function Tools() {
/>
</div>
<button
className="rounded-full w-40 bg-purple-30 px-4 py-3 text-white hover:bg-[#6F3FD1] text-nowrap"
className="rounded-full min-w-[160px] bg-purple-30 px-6 py-3 text-white hover:bg-[#6F3FD1] text-nowrap"
onClick={() => {
setAddToolModalState('ACTIVE');
}}
@@ -103,7 +103,7 @@ export default function Tools() {
<div className="mt-24 col-span-2 lg:col-span-3 text-center text-gray-500 dark:text-gray-400">
<img
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
alt={t('settings.tools.noToolsFound')}
alt="No tools found"
className="h-24 w-24 mx-auto mb-2"
/>
{t('settings.tools.noToolsFound')}

View File

@@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import userService from '../api/services/userService';
import ArrowLeft from '../assets/arrow-left.svg';
import FileUpload from '../assets/file_upload.svg';
import WebsiteCollect from '../assets/website_collect.svg';
import Dropdown from '../components/Dropdown';
@@ -55,11 +54,11 @@ function Upload({
const setTimeoutRef = useRef<number | null>();
const urlOptions: { label: string; value: string }[] = [
{ label: 'Crawler', value: 'crawler' },
// { label: 'Sitemap', value: 'sitemap' },
{ label: 'Link', value: 'url' },
{ label: 'Reddit', value: 'reddit' },
{ label: 'GitHub', value: 'github' }, // P3f93
{ label: `Crawler`, value: 'crawler' },
// { label: t('modals.uploadDoc.sitemap'), value: 'sitemap' },
{ label: `Link`, value: 'url' },
{ label: `GitHub`, value: 'github' },
{ label: `Reddit`, value: 'reddit' },
];
const [urlType, setUrlType] = useState<{ label: string; value: string }>({
@@ -114,12 +113,14 @@ function Upload({
<div className="mt-5 flex flex-col items-center gap-2 text-gray-2000 dark:text-bright-gray">
<p className="text-gra text-xl tracking-[0.15px]">
{isTraining &&
(progress?.percentage === 100 ? 'Training completed' : title)}
(progress?.percentage === 100
? t('modals.uploadDoc.progress.completed')
: title)}
{!isTraining && title}
</p>
<p className="text-sm">This may take several minutes</p>
<p className="text-sm">{t('modals.uploadDoc.progress.wait')}</p>
<p className={`ml-5 text-xl text-red-400 ${isFailed ? '' : 'hidden'}`}>
Over the token limit, please consider uploading smaller document
{t('modals.uploadDoc.progress.tokenLimit')}
</p>
{/* <p className="mt-10 text-2xl">{progress?.percentage || 0}%</p> */}
<ProgressBar progressPercent={progress?.percentage || 0} />
@@ -149,7 +150,7 @@ function Upload({
}
function UploadProgress() {
return <Progress title="Upload is in progress"></Progress>;
return <Progress title={t('modals.uploadDoc.progress.upload')}></Progress>;
}
function TrainingProgress() {
@@ -240,7 +241,7 @@ function Upload({
}, [progress, dispatch]);
return (
<Progress
title="Training is in progress"
title={t('modals.uploadDoc.progress.training')}
isCancellable={progress?.percentage === 100}
isFailed={progress?.failed === true}
isTraining={true}
@@ -510,7 +511,7 @@ function Upload({
<div className="flex flex-col gap-1 mt-2">
<div>
<Input
placeholder="Enter client ID"
placeholder={t('modals.uploadDoc.reddit.id')}
type="text"
name="client_id"
value={redditData.client_id}
@@ -525,7 +526,7 @@ function Upload({
</div>
<div>
<Input
placeholder="Enter client secret"
placeholder={t('modals.uploadDoc.reddit.secret')}
type="text"
name="client_secret"
value={redditData.client_secret}
@@ -540,7 +541,7 @@ function Upload({
</div>
<div>
<Input
placeholder="Enter user agent"
placeholder={t('modals.uploadDoc.reddit.agent')}
type="text"
name="user_agent"
value={redditData.user_agent}
@@ -555,7 +556,7 @@ function Upload({
</div>
<div>
<Input
placeholder="Enter search queries"
placeholder={t('modals.uploadDoc.reddit.searchQueries')}
type="text"
name="search_queries"
value={redditData.search_queries}
@@ -570,7 +571,7 @@ function Upload({
</div>
<div>
<Input
placeholder="Enter number of posts"
placeholder={t('modals.uploadDoc.reddit.numberOfPosts')}
type="number"
name="number_posts"
value={redditData.number_posts}
@@ -587,70 +588,57 @@ function Upload({
)}
</>
)}
{activeTab && (
<div className="flex w-full justify-between flex-row-reverse">
{activeTab === 'file' ? (
<button
onClick={uploadFile}
className={`ml-2 cursor-pointer rounded-3xl bg-purple-30 text-sm text-white ${
files.length > 0 && docName.trim().length > 0
? 'hover:bg-[#6F3FD1]'
: 'bg-opacity-75 text-opacity-80'
} py-2 px-6`}
disabled={
(files.length === 0 || docName.trim().length === 0) &&
activeTab === 'file'
}
>
{t('modals.uploadDoc.train')}
</button>
) : (
<button
onClick={uploadRemote}
className={`ml-2 cursor-pointer rounded-3xl bg-purple-30 py-2 px-6 text-sm text-white hover:bg-[#6F3FD1] ${
urlName.trim().length === 0 ||
url.trim().length === 0 ||
(urlType.label === 'Reddit' &&
(redditData.client_id.length === 0 ||
redditData.client_secret.length === 0 ||
redditData.user_agent.length === 0 ||
redditData.search_queries.length === 0 ||
redditData.number_posts === 0)) ||
(urlType.label === 'GitHub' && repoUrl.trim().length === 0)
? 'bg-opacity-80 text-opacity-80'
: ''
}`}
disabled={
urlName.trim().length === 0 ||
url.trim().length === 0 ||
(urlType.label === 'Reddit' &&
(redditData.client_id.length === 0 ||
redditData.client_secret.length === 0 ||
redditData.user_agent.length === 0 ||
redditData.search_queries.length === 0 ||
redditData.number_posts === 0)) ||
(urlType.label === 'GitHub' && repoUrl.trim().length === 0)
}
>
{t('modals.uploadDoc.train')}
</button>
)}
<div className="flex justify-between">
{activeTab && (
<button
onClick={() => {
setDocName('');
setfiles([]);
setActiveTab(null);
}}
className="cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:text-light-gray dark:hover:bg-[#767183]/50 flex items-center gap-1"
onClick={() => setActiveTab(null)}
className="rounded-3xl border border-purple-30 px-4 py-2 font-medium text-purple-30 hover:cursor-pointer dark:bg-purple-taupe dark:text-silver"
>
<img
src={ArrowLeft}
className="w-[10px] h-[10px] dark:filter dark:invert"
/>
{t('modals.uploadDoc.back')}
</button>
</div>
)}
)}
<button
onClick={() => {
if (activeTab === 'file') {
uploadFile();
} else {
uploadRemote();
}
}}
disabled={
(activeTab === 'file' && (!files.length || !docName)) ||
(activeTab === 'remote' &&
((urlType.label !== 'Reddit' &&
urlType.label !== 'GitHub' &&
(!url || !urlName)) ||
(urlType.label === 'GitHub' && !repoUrl) ||
(urlType.label === 'Reddit' &&
(!redditData.client_id ||
!redditData.client_secret ||
!redditData.user_agent ||
!redditData.search_queries ||
!redditData.number_posts))))
}
className={`rounded-3xl px-4 py-2 font-medium ${
(activeTab === 'file' && (!files.length || !docName)) ||
(activeTab === 'remote' &&
((urlType.label !== 'Reddit' &&
urlType.label !== 'GitHub' &&
(!url || !urlName)) ||
(urlType.label === 'GitHub' && !repoUrl) ||
(urlType.label === 'Reddit' &&
(!redditData.client_id ||
!redditData.client_secret ||
!redditData.user_agent ||
!redditData.search_queries ||
!redditData.number_posts))))
? 'cursor-not-allowed bg-gray-300 text-gray-500'
: 'cursor-pointer bg-purple-30 text-white hover:bg-purple-40'
}`}
>
{t('modals.uploadDoc.train')}
</button>
</div>
</div>
);
}