Merge pull request #1821 from ManishMadan2882/main

Chore: Frontend refinements, i18n sync
This commit is contained in:
Alex
2025-06-02 10:13:02 +01:00
committed by GitHub
15 changed files with 310 additions and 329 deletions

View File

@@ -1,99 +0,0 @@
//TODO - Add hyperlinks to text
//TODO - Styling
import DocsGPT3 from './assets/cute_docsgpt3.svg';
export default function About() {
return (
<div className="mx-5 grid min-h-screen md:mx-36">
<article className="place-items-left mx-auto my-auto flex w-full max-w-6xl flex-col gap-4 rounded-3xl bg-gray-100 p-6 text-jet dark:bg-gun-metal dark:text-bright-gray lg:p-6 xl:p-10">
<div className="flex items-center">
<p className="mr-2 text-3xl">About DocsGPT</p>
<img className="h14 mb-2" src={DocsGPT3} alt="DocsGPT" />
</div>
<p className="mt-4">
Find the information in your documentation through AI-powered
<a
className="text-blue-500"
href="https://github.com/arc53/DocsGPT"
target="_blank"
rel="noreferrer"
>
{' '}
open-source{' '}
</a>
chatbot. Powered by GPT-3, Faiss and LangChain.
</p>
<div>
<p>
If you want to add your own documentation, please follow the
instruction below:
</p>
<p className="ml-2 mt-4">
1. Navigate to{' '}
<span className="bg-gray-200 italic dark:bg-outer-space">
{' '}
/application
</span>{' '}
folder
</p>
<p className="ml-2 mt-4">
2. Install dependencies from{' '}
<span className="bg-gray-200 italic dark:bg-outer-space">
pip install -r requirements.txt
</span>
</p>
<p className="ml-2 mt-4">
3. Prepare a{' '}
<span className="bg-gray-200 italic dark:bg-outer-space">.env</span>{' '}
file. Copy{' '}
<span className="bg-gray-200 italic dark:bg-outer-space">
.env_sample
</span>{' '}
and create{' '}
<span className="bg-gray-200 italic dark:bg-outer-space">.env</span>{' '}
with your OpenAI API token
</p>
<p className="ml-2 mt-4">
4. Run the app with{' '}
<span className="bg-gray-200 italic dark:bg-outer-space">
python app.py
</span>
</p>
</div>
<p>
Currently It uses{' '}
<span className="font-medium text-blue-950">DocsGPT</span>{' '}
documentation, so it will respond to information relevant to{' '}
<span className="font-medium text-blue-950">DocsGPT</span>. If you
want to train it on different documentation - please follow
<a
className="text-blue-500"
href="https://github.com/arc53/DocsGPT/wiki/How-to-train-on-other-documentation"
target="_blank"
rel="noreferrer"
>
{' '}
this guide
</a>
.
</p>
<p className="mt-4 text-left">
If you want to launch it on your own server - follow
<a
className="text-blue-500"
href="https://github.com/arc53/DocsGPT/wiki/Hosting-the-app"
target="_blank"
rel="noreferrer"
>
{' '}
this guide
</a>
.
</p>
</article>
</div>
);
}

View File

@@ -2,8 +2,6 @@ import './locale/i18n';
import { useState } from 'react'; import { useState } from 'react';
import { Outlet, Route, Routes } from 'react-router-dom'; import { Outlet, Route, Routes } from 'react-router-dom';
import About from './About';
import Spinner from './components/Spinner'; import Spinner from './components/Spinner';
import Conversation from './conversation/Conversation'; import Conversation from './conversation/Conversation';
import { SharedConversation } from './conversation/SharedConversation'; import { SharedConversation } from './conversation/SharedConversation';
@@ -29,8 +27,8 @@ function AuthWrapper({ children }: { children: React.ReactNode }) {
} }
function MainLayout() { function MainLayout() {
const { isMobile } = useMediaQuery(); const { isMobile, isTablet } = useMediaQuery();
const [navOpen, setNavOpen] = useState(!isMobile); const [navOpen, setNavOpen] = useState(!(isMobile || isTablet));
return ( return (
<div className="relative h-screen overflow-hidden dark:bg-raisin-black"> <div className="relative h-screen overflow-hidden dark:bg-raisin-black">
@@ -38,7 +36,7 @@ function MainLayout() {
<ActionButtons showNewChat={true} showShare={true} /> <ActionButtons showNewChat={true} showShare={true} />
<div <div
className={`h-[calc(100dvh-64px)] overflow-auto lg:h-screen ${ className={`h-[calc(100dvh-64px)] overflow-auto lg:h-screen ${
!isMobile !(isMobile || isTablet)
? `ml-0 ${!navOpen ? 'lg:mx-auto' : 'lg:ml-72'}` ? `ml-0 ${!navOpen ? 'lg:mx-auto' : 'lg:ml-72'}`
: 'ml-0 lg:ml-16' : 'ml-0 lg:ml-16'
}`} }`}
@@ -64,7 +62,6 @@ export default function App() {
} }
> >
<Route index element={<Conversation />} /> <Route index element={<Conversation />} />
<Route path="/about" element={<About />} />
<Route path="/settings/*" element={<Setting />} /> <Route path="/settings/*" element={<Setting />} />
<Route path="/agents/*" element={<Agents />} /> <Route path="/agents/*" element={<Agents />} />
</Route> </Route>

View File

@@ -71,7 +71,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const sharedAgents = useSelector(selectSharedAgents); const sharedAgents = useSelector(selectSharedAgents);
const selectedAgent = useSelector(selectSelectedAgent); const selectedAgent = useSelector(selectSelectedAgent);
const { isMobile } = useMediaQuery(); const { isMobile, isTablet } = useMediaQuery();
const [isDarkTheme] = useDarkTheme(); const [isDarkTheme] = useDarkTheme();
const { showTokenModal, handleTokenSubmit } = useTokenAuth(); const { showTokenModal, handleTokenSubmit } = useTokenAuth();
@@ -162,7 +162,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const handleAgentClick = (agent: Agent) => { const handleAgentClick = (agent: Agent) => {
resetConversation(); resetConversation();
dispatch(setSelectedAgent(agent)); dispatch(setSelectedAgent(agent));
if (isMobile) setNavOpen(!navOpen); if (isMobile || isTablet) setNavOpen(!navOpen);
navigate('/'); navigate('/');
}; };
@@ -197,6 +197,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
query: { conversationId: index }, query: { conversationId: index },
}), }),
); );
if (isMobile || isTablet) {
setNavOpen(false);
}
if (data.agent_id) { if (data.agent_id) {
if (data.is_shared_usage) { if (data.is_shared_usage) {
userService userService
@@ -271,8 +274,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
} }
useEffect(() => { useEffect(() => {
setNavOpen(!isMobile); setNavOpen(!(isMobile || isTablet));
}, [isMobile]); }, [isMobile, isTablet]);
useDefaultDocument(); useDefaultDocument();
return ( return (
@@ -352,7 +355,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<NavLink <NavLink
to={'/'} to={'/'}
onClick={() => { onClick={() => {
if (isMobile) { if (isMobile || isTablet) {
setNavOpen(!navOpen); setNavOpen(!navOpen);
} }
resetConversation(); resetConversation();
@@ -415,7 +418,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
</p> </p>
</div> </div>
<div <div
className={`${isMobile ? 'flex' : 'invisible flex group-hover:visible'} items-center px-3`} className={`${isMobile || isTablet ? 'flex' : 'invisible flex group-hover:visible'} items-center px-3`}
> >
<button <button
className="rounded-full hover:opacity-75" className="rounded-full hover:opacity-75"
@@ -437,6 +440,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
className="mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal" className="mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal"
onClick={() => { onClick={() => {
dispatch(setSelectedAgent(null)); dispatch(setSelectedAgent(null));
if (isMobile || isTablet) {
setNavOpen(false);
}
navigate('/agents'); navigate('/agents');
}} }}
> >
@@ -448,7 +454,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
/> />
</div> </div>
<p className="overflow-hidden overflow-ellipsis whitespace-nowrap text-sm leading-6 text-eerie-black dark:text-bright-gray"> <p className="overflow-hidden overflow-ellipsis whitespace-nowrap text-sm leading-6 text-eerie-black dark:text-bright-gray">
Manage Agents {t('manageAgents')}
</p> </p>
</div> </div>
</div> </div>
@@ -456,7 +462,13 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
) : ( ) : (
<div <div
className="mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal" className="mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal"
onClick={() => navigate('/agents')} onClick={() => {
if (isMobile || isTablet) {
setNavOpen(false);
}
dispatch(setSelectedAgent(null));
navigate('/agents');
}}
> >
<div className="flex w-6 justify-center"> <div className="flex w-6 justify-center">
<img <img
@@ -466,7 +478,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
/> />
</div> </div>
<p className="overflow-hidden overflow-ellipsis whitespace-nowrap text-sm leading-6 text-eerie-black dark:text-bright-gray"> <p className="overflow-hidden overflow-ellipsis whitespace-nowrap text-sm leading-6 text-eerie-black dark:text-bright-gray">
Manage Agents {t('manageAgents')}
</p> </p>
</div> </div>
)} )}
@@ -502,8 +514,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
<div className="flex flex-col gap-2 border-b-[1px] py-2 dark:border-b-purple-taupe"> <div className="flex flex-col gap-2 border-b-[1px] py-2 dark:border-b-purple-taupe">
<NavLink <NavLink
onClick={() => { onClick={() => {
if (isMobile) { if (isMobile || isTablet) {
setNavOpen(!navOpen); setNavOpen(false);
} }
resetConversation(); resetConversation();
}} }}

View File

@@ -207,7 +207,7 @@ export default function SourcesPopup({
className="inline-flex items-center gap-2 text-base font-medium text-violets-are-blue" className="inline-flex items-center gap-2 text-base font-medium text-violets-are-blue"
onClick={onClose} onClick={onClose}
> >
Go to Documents {t('settings.documents.goToDocuments')}
<img src={RedirectIcon} alt="Redirect" className="h-3 w-3" /> <img src={RedirectIcon} alt="Redirect" className="h-3 w-3" />
</a> </a>
</div> </div>
@@ -217,7 +217,7 @@ export default function SourcesPopup({
onClick={handleUploadClick} onClick={handleUploadClick}
className="w-auto rounded-full border border-violets-are-blue px-4 py-2 text-[14px] font-medium text-violets-are-blue transition-colors duration-200 hover:bg-violets-are-blue hover:text-white" className="w-auto rounded-full border border-violets-are-blue px-4 py-2 text-[14px] font-medium text-violets-are-blue transition-colors duration-200 hover:bg-violets-are-blue hover:text-white"
> >
Upload new {t('settings.documents.uploadNew')}
</button> </button>
</div> </div>
</div> </div>

View File

@@ -35,8 +35,8 @@ export function useOutsideAlerter<T extends HTMLElement>(
export function useMediaQuery() { export function useMediaQuery() {
const mobileQuery = '(max-width: 768px)'; const mobileQuery = '(max-width: 768px)';
const tabletQuery = '(max-width: 1024px)'; // Tablet breakpoint at 1024px const tabletQuery = '(max-width: 1023px)';
const desktopQuery = '(min-width: 1025px)'; // Desktop starts after tablet const desktopQuery = '(min-width: 1024px)';
const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);
const [isTablet, setIsTablet] = useState(false); const [isTablet, setIsTablet] = useState(false);
const [isDesktop, setIsDesktop] = useState(false); const [isDesktop, setIsDesktop] = useState(false);

View File

@@ -77,7 +77,9 @@
"backToAll": "Back to all documents", "backToAll": "Back to all documents",
"chunks": "Chunks", "chunks": "Chunks",
"noChunks": "No chunks found", "noChunks": "No chunks found",
"noChunksAlt": "No chunks found" "noChunksAlt": "No chunks found",
"goToDocuments": "Go to Documents",
"uploadNew": "Upload new"
}, },
"apiKeys": { "apiKeys": {
"label": "Chatbots", "label": "Chatbots",
@@ -138,7 +140,7 @@
"addAction": "Add action", "addAction": "Add action",
"noActionsFound": "No actions found", "noActionsFound": "No actions found",
"url": "URL", "url": "URL",
"urlPlaceholder": "Enter url", "urlPlaceholder": "Enter URL",
"method": "Method", "method": "Method",
"description": "Description", "description": "Description",
"descriptionPlaceholder": "Enter description", "descriptionPlaceholder": "Enter description",
@@ -146,15 +148,20 @@
"queryParameters": "Query Parameters", "queryParameters": "Query Parameters",
"body": "Body", "body": "Body",
"deleteActionWarning": "Are you sure you want to delete the action \"{{name}}\"?", "deleteActionWarning": "Are you sure you want to delete the action \"{{name}}\"?",
"backToTools": "Back to Tools", "backToAllTools": "Back to all tools",
"save": "Save", "save": "Save",
"name": "Name", "fieldName": "Field Name",
"type": "Type", "fieldType": "Field Type",
"filledByLLM": "Filled by LLM", "filledByLLM": "Filled by LLM",
"fieldDescription": "Field description",
"value": "Value", "value": "Value",
"addProperty": "Add property", "addProperty": "Add property",
"propertyName": "Property name", "propertyName": "New property key",
"noProperties": "No properties" "add": "Add",
"cancel": "Cancel",
"addNew": "Add New",
"name": "Name",
"type": "Type"
} }
}, },
"modals": { "modals": {
@@ -239,6 +246,18 @@
"promptText": "Prompt Text", "promptText": "Prompt Text",
"save": "Save", "save": "Save",
"nameExists": "Name already exists" "nameExists": "Name already exists"
},
"chunk": {
"add": "Add Chunk",
"edit": "Edit Chunk",
"title": "Title",
"enterTitle": "Enter title",
"bodyText": "Body text",
"promptText": "Prompt Text",
"update": "Update",
"close": "Close",
"delete": "Delete",
"deleteConfirmation": "Are you sure you want to delete this chunk?"
} }
}, },
"sharedConv": { "sharedConv": {

View File

@@ -11,6 +11,7 @@
"help": "Asistencia", "help": "Asistencia",
"emailUs": "Envíanos un correo", "emailUs": "Envíanos un correo",
"documentation": "Documentación", "documentation": "Documentación",
"manageAgents": "Administrar Agentes",
"demo": [ "demo": [
{ {
"header": "Aprende sobre DocsGPT", "header": "Aprende sobre DocsGPT",
@@ -48,7 +49,8 @@
"medium": "Medio", "medium": "Medio",
"high": "Alto", "high": "Alto",
"unlimited": "Ilimitado", "unlimited": "Ilimitado",
"default": "Predeterminado" "default": "Predeterminado",
"addNew": "Añadir Nuevo"
}, },
"documents": { "documents": {
"title": "Esta tabla contiene todos los documentos que están disponibles para ti y los que has subido", "title": "Esta tabla contiene todos los documentos que están disponibles para ti y los que has subido",
@@ -75,7 +77,9 @@
"backToAll": "Volver a todos los documentos", "backToAll": "Volver a todos los documentos",
"chunks": "Fragmentos", "chunks": "Fragmentos",
"noChunks": "No se encontraron fragmentos", "noChunks": "No se encontraron fragmentos",
"noChunksAlt": "No se encontraron fragmentos" "noChunksAlt": "No se encontraron fragmentos",
"goToDocuments": "Ir a Documentos",
"uploadNew": "Subir nuevo"
}, },
"apiKeys": { "apiKeys": {
"label": "Chatbots", "label": "Chatbots",
@@ -144,15 +148,20 @@
"queryParameters": "Parámetros de Consulta", "queryParameters": "Parámetros de Consulta",
"body": "Cuerpo", "body": "Cuerpo",
"deleteActionWarning": "¿Estás seguro de que deseas eliminar la acción \"{{name}}\"?", "deleteActionWarning": "¿Estás seguro de que deseas eliminar la acción \"{{name}}\"?",
"backToTools": "Volver a Herramientas",
"save": "Guardar", "save": "Guardar",
"name": "Nombre", "name": "Nombre",
"type": "Tipo", "type": "Tipo",
"filledByLLM": "Completado por LLM", "filledByLLM": "Completado por LLM",
"value": "Valor", "value": "Valor",
"addProperty": "Agregar propiedad", "addProperty": "Agregar propiedad",
"propertyName": "Nombre de propiedad", "propertyName": "Nueva clave de propiedad",
"noProperties": "Sin propiedades" "backToAllTools": "Volver a todas las herramientas",
"fieldName": "Nombre del campo",
"fieldType": "Tipo de campo",
"fieldDescription": "Descripción del campo",
"add": "Añadir",
"cancel": "Cancelar",
"addNew": "Añadir Nuevo"
} }
}, },
"modals": { "modals": {
@@ -237,6 +246,18 @@
"promptText": "Texto del Prompt", "promptText": "Texto del Prompt",
"save": "Guardar", "save": "Guardar",
"nameExists": "El nombre ya existe" "nameExists": "El nombre ya existe"
},
"chunk": {
"add": "Agregar Fragmento",
"edit": "Editar Fragmento",
"title": "Título",
"enterTitle": "Ingresar título",
"bodyText": "Texto del cuerpo",
"promptText": "Texto del prompt",
"update": "Actualizar",
"close": "Cerrar",
"delete": "Eliminar",
"deleteConfirmation": "¿Estás seguro de que deseas eliminar este fragmento?"
} }
}, },
"sharedConv": { "sharedConv": {
@@ -270,9 +291,9 @@
}, },
"sources": { "sources": {
"title": "Fuentes", "title": "Fuentes",
"text": "Texto fuente",
"link": "Enlace fuente", "link": "Enlace fuente",
"view_more": "Ver {{count}} más fuentes" "view_more": "Ver {{count}} más fuentes",
"text": "Elegir tus fuentes"
}, },
"attachments": { "attachments": {
"attach": "Adjuntar", "attach": "Adjuntar",

View File

@@ -11,6 +11,7 @@
"help": "ヘルプ", "help": "ヘルプ",
"emailUs": "メールを送る", "emailUs": "メールを送る",
"documentation": "ドキュメント", "documentation": "ドキュメント",
"manageAgents": "エージェント管理",
"demo": [ "demo": [
{ {
"header": "DocsGPTについて学ぶ", "header": "DocsGPTについて学ぶ",
@@ -76,7 +77,9 @@
"backToAll": "すべてのドキュメントに戻る", "backToAll": "すべてのドキュメントに戻る",
"chunks": "チャンク", "chunks": "チャンク",
"noChunks": "チャンクが見つかりません", "noChunks": "チャンクが見つかりません",
"noChunksAlt": "チャンクが見つかりません" "noChunksAlt": "チャンクが見つかりません",
"goToDocuments": "ドキュメントへ移動",
"uploadNew": "新規アップロード"
}, },
"apiKeys": { "apiKeys": {
"label": "チャットボット", "label": "チャットボット",
@@ -101,7 +104,6 @@
}, },
"messages": "メッセージ", "messages": "メッセージ",
"tokenUsage": "トークン使用量", "tokenUsage": "トークン使用量",
"feedback": "フィードバック",
"filterPlaceholder": "フィルター", "filterPlaceholder": "フィルター",
"none": "なし", "none": "なし",
"positiveFeedback": "肯定的なフィードバック", "positiveFeedback": "肯定的なフィードバック",
@@ -146,15 +148,20 @@
"queryParameters": "クエリパラメータ", "queryParameters": "クエリパラメータ",
"body": "ボディ", "body": "ボディ",
"deleteActionWarning": "アクション \"{{name}}\" を削除してもよろしいですか?", "deleteActionWarning": "アクション \"{{name}}\" を削除してもよろしいですか?",
"backToTools": "ツールに戻る", "backToAllTools": "すべてのツールに戻る",
"save": "保存", "save": "保存",
"name": "名", "fieldName": "フィールド名",
"type": "タイプ", "fieldType": "フィールドタイプ",
"filledByLLM": "LLMによる入力", "filledByLLM": "LLMによる入力",
"fieldDescription": "フィールドの説明",
"value": "値", "value": "値",
"addProperty": "プロパティを追加", "addProperty": "プロパティを追加",
"propertyName": "プロパティ", "propertyName": "新しいプロパティキー",
"noProperties": "プロパティなし" "add": "追加",
"cancel": "キャンセル",
"addNew": "新規追加",
"name": "名前",
"type": "タイプ"
} }
}, },
"modals": { "modals": {
@@ -239,6 +246,18 @@
"promptText": "プロンプトテキスト", "promptText": "プロンプトテキスト",
"save": "保存", "save": "保存",
"nameExists": "名前が既に存在します" "nameExists": "名前が既に存在します"
},
"chunk": {
"add": "チャンクを追加",
"edit": "チャンクを編集",
"title": "タイトル",
"enterTitle": "タイトルを入力",
"bodyText": "本文",
"promptText": "プロンプトテキスト",
"update": "更新",
"close": "閉じる",
"delete": "削除",
"deleteConfirmation": "このチャンクを削除してもよろしいですか?"
} }
}, },
"sharedConv": { "sharedConv": {

View File

@@ -11,6 +11,7 @@
"help": "Помощь", "help": "Помощь",
"emailUs": "Напишите нам", "emailUs": "Напишите нам",
"documentation": "Документация", "documentation": "Документация",
"manageAgents": "Управление агентами",
"demo": [ "demo": [
{ {
"header": "Узнайте о DocsGPT", "header": "Узнайте о DocsGPT",
@@ -76,7 +77,9 @@
"backToAll": "Вернуться ко всем документам", "backToAll": "Вернуться ко всем документам",
"chunks": "Фрагменты", "chunks": "Фрагменты",
"noChunks": "Фрагменты не найдены", "noChunks": "Фрагменты не найдены",
"noChunksAlt": "Фрагменты не найдены" "noChunksAlt": "Фрагменты не найдены",
"goToDocuments": "Перейти к документам",
"uploadNew": "Загрузить новый"
}, },
"apiKeys": { "apiKeys": {
"label": "API ключи", "label": "API ключи",
@@ -137,23 +140,28 @@
"addAction": "Добавить действие", "addAction": "Добавить действие",
"noActionsFound": "Действия не найдены", "noActionsFound": "Действия не найдены",
"url": "URL", "url": "URL",
"urlPlaceholder": "Введите url", "urlPlaceholder": "Введите URL",
"method": "Метод", "method": "Метод",
"description": "Описание", "description": "Описание",
"descriptionPlaceholder": "Введите описание", "descriptionPlaceholder": "Введите описание",
"headers": "Заголовки", "headers": "Заголовки",
"queryParameters": "Параметры запроса", "queryParameters": "Параметры запроса",
"body": "Тело", "body": "Тело запроса",
"deleteActionWarning": "Вы уверены, что хотите удалить действие \"{{name}}\"?", "deleteActionWarning": "Вы уверены, что хотите удалить действие \"{{name}}\"?",
"backToTools": "Вернуться к инструментам", "backToAllTools": "Вернуться ко всем инструментам",
"save": "Сохранить", "save": "Сохранить",
"name": "Имя", "fieldName": "Имя поля",
"type": "Тип", "fieldType": "Тип поля",
"filledByLLM": "Заполнено LLM", "filledByLLM": "Заполняется LLM",
"fieldDescription": "Описание поля",
"value": "Значение", "value": "Значение",
"addProperty": "Добавить свойство", "addProperty": "Добавить свойство",
"propertyName": "Имя свойства", "propertyName": "Новый ключ свойства",
"noProperties": "Нет свойств" "add": "Добавить",
"cancel": "Отмена",
"addNew": "Добавить новое",
"name": "Имя",
"type": "Тип"
} }
}, },
"modals": { "modals": {
@@ -238,6 +246,18 @@
"promptText": "Текст подсказки", "promptText": "Текст подсказки",
"save": "Сохранить", "save": "Сохранить",
"nameExists": "Название уже существует" "nameExists": "Название уже существует"
},
"chunk": {
"add": "Добавить фрагмент",
"edit": "Редактировать фрагмент",
"title": "Заголовок",
"enterTitle": "Введите заголовок",
"bodyText": "Текст",
"promptText": "Текст подсказки",
"update": "Обновить",
"close": "Закрыть",
"delete": "Удалить",
"deleteConfirmation": "Вы уверены, что хотите удалить этот фрагмент?"
} }
}, },
"sharedConv": { "sharedConv": {
@@ -271,7 +291,7 @@
}, },
"sources": { "sources": {
"title": "Источники", "title": "Источники",
"text": "Текст источника", "text": "Выберите ваши источники",
"link": "Ссылка на источник", "link": "Ссылка на источник",
"view_more": "ещё {{count}} источников" "view_more": "ещё {{count}} источников"
}, },

View File

@@ -11,6 +11,7 @@
"help": "幫助", "help": "幫助",
"emailUs": "給我們發電郵", "emailUs": "給我們發電郵",
"documentation": "文件", "documentation": "文件",
"manageAgents": "管理代理",
"demo": [ "demo": [
{ {
"header": "了解 DocsGPT", "header": "了解 DocsGPT",
@@ -76,7 +77,9 @@
"backToAll": "返回所有文件", "backToAll": "返回所有文件",
"chunks": "文本塊", "chunks": "文本塊",
"noChunks": "未找到文本塊", "noChunks": "未找到文本塊",
"noChunksAlt": "未找到文本塊" "noChunksAlt": "未找到文本塊",
"goToDocuments": "前往文件",
"uploadNew": "上傳新文件"
}, },
"apiKeys": { "apiKeys": {
"label": "聊天機器人", "label": "聊天機器人",
@@ -145,15 +148,20 @@
"queryParameters": "查詢參數", "queryParameters": "查詢參數",
"body": "主體", "body": "主體",
"deleteActionWarning": "您確定要刪除操作 \"{{name}}\" 嗎?", "deleteActionWarning": "您確定要刪除操作 \"{{name}}\" 嗎?",
"backToTools": "返回工具", "backToAllTools": "返回所有工具",
"save": "儲存", "save": "儲存",
"name": "名稱", "fieldName": "欄位名稱",
"type": "類型", "fieldType": "欄位類型",
"filledByLLM": "由LLM填", "filledByLLM": "由LLM填",
"fieldDescription": "欄位描述",
"value": "值", "value": "值",
"addProperty": "新增屬性", "addProperty": "新增屬性",
"propertyName": "屬性名稱", "propertyName": "屬性",
"noProperties": "無屬性" "add": "新增",
"cancel": "取消",
"addNew": "新增",
"name": "名稱",
"type": "類型"
} }
}, },
"modals": { "modals": {
@@ -238,6 +246,18 @@
"promptText": "提示文字", "promptText": "提示文字",
"save": "儲存", "save": "儲存",
"nameExists": "名稱已存在" "nameExists": "名稱已存在"
},
"chunk": {
"add": "新增區塊",
"edit": "編輯區塊",
"title": "標題",
"enterTitle": "輸入標題",
"bodyText": "內文",
"promptText": "提示文字",
"update": "更新",
"close": "關閉",
"delete": "刪除",
"deleteConfirmation": "您確定要刪除此區塊嗎?"
} }
}, },
"sharedConv": { "sharedConv": {

View File

@@ -11,6 +11,7 @@
"help": "帮助", "help": "帮助",
"emailUs": "给我们发邮件", "emailUs": "给我们发邮件",
"documentation": "文档", "documentation": "文档",
"manageAgents": "管理代理",
"demo": [ "demo": [
{ {
"header": "了解 DocsGPT", "header": "了解 DocsGPT",
@@ -72,7 +73,13 @@
}, },
"actions": "操作", "actions": "操作",
"view": "查看", "view": "查看",
"deleteWarning": "您确定要删除 \"{{name}}\" 吗?" "deleteWarning": "您确定要删除 \"{{name}}\" 吗?",
"backToAll": "返回所有文档",
"chunks": "文本块",
"noChunks": "未找到文本块",
"noChunksAlt": "未找到文本块",
"goToDocuments": "前往文档",
"uploadNew": "上传新文档"
}, },
"apiKeys": { "apiKeys": {
"label": "聊天机器人", "label": "聊天机器人",
@@ -141,15 +148,20 @@
"queryParameters": "查询参数", "queryParameters": "查询参数",
"body": "请求体", "body": "请求体",
"deleteActionWarning": "您确定要删除操作 \"{{name}}\" 吗?", "deleteActionWarning": "您确定要删除操作 \"{{name}}\" 吗?",
"backToTools": "返回工具", "backToAllTools": "返回所有工具",
"save": "保存", "save": "保存",
"name": "名称", "fieldName": "字段名称",
"type": "类型", "fieldType": "字段类型",
"filledByLLM": "由LLM填充", "filledByLLM": "由LLM填充",
"fieldDescription": "字段描述",
"value": "值", "value": "值",
"addProperty": "添加属性", "addProperty": "添加属性",
"propertyName": "属性名称", "propertyName": "属性",
"noProperties": "无属性" "add": "添加",
"cancel": "取消",
"addNew": "添加新的",
"name": "名称",
"type": "类型"
} }
}, },
"modals": { "modals": {
@@ -234,6 +246,18 @@
"promptText": "提示文本", "promptText": "提示文本",
"save": "保存", "save": "保存",
"nameExists": "名称已存在" "nameExists": "名称已存在"
},
"chunk": {
"add": "添加块",
"edit": "编辑块",
"title": "标题",
"enterTitle": "输入标题",
"bodyText": "正文",
"promptText": "提示文本",
"update": "更新",
"close": "关闭",
"delete": "删除",
"deleteConfirmation": "您确定要删除此块吗?"
} }
}, },
"sharedConv": { "sharedConv": {

View File

@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next';
import Exit from '../assets/exit.svg';
import Input from '../components/Input'; import Input from '../components/Input';
import { ActiveState } from '../models/misc'; import { ActiveState } from '../models/misc';
import ConfirmationModal from './ConfirmationModal'; import ConfirmationModal from './ConfirmationModal';
import WrapperModal from './WrapperModal';
export default function ChunkModal({ export default function ChunkModal({
type, type,
@@ -22,6 +23,7 @@ export default function ChunkModal({
originalText?: string; originalText?: string;
handleDelete?: () => void; handleDelete?: () => void;
}) { }) {
const { t } = useTranslation();
const [title, setTitle] = React.useState(''); const [title, setTitle] = React.useState('');
const [chunkText, setChunkText] = React.useState(''); const [chunkText, setChunkText] = React.useState('');
const [deleteModal, setDeleteModal] = React.useState<ActiveState>('INACTIVE'); const [deleteModal, setDeleteModal] = React.useState<ActiveState>('INACTIVE');
@@ -30,157 +32,105 @@ export default function ChunkModal({
setTitle(originalTitle || ''); setTitle(originalTitle || '');
setChunkText(originalText || ''); setChunkText(originalText || '');
}, [originalTitle, originalText]); }, [originalTitle, originalText]);
if (type === 'ADD') {
return ( if (modalState !== 'ACTIVE') return null;
<div
className={`${ const content = (
modalState === 'ACTIVE' ? 'visible' : 'hidden' <div>
} fixed left-0 top-0 z-30 flex h-screen w-screen items-center justify-center bg-gray-alpha`} <h2 className="px-3 text-xl font-semibold text-jet dark:text-bright-gray">
> {t(`modals.chunk.${type === 'ADD' ? 'add' : 'edit'}`)}
<article className="flex w-11/12 flex-col gap-4 rounded-2xl bg-white shadow-lg dark:bg-[#26272E] sm:w-[620px]"> </h2>
<div className="relative"> <div className="relative mt-6 px-3">
<button <Input
className="absolute right-4 top-3 m-2 w-3" type="text"
onClick={() => { value={title}
setModalState('INACTIVE'); onChange={(e) => setTitle(e.target.value)}
}} borderVariant="thin"
> placeholder={t('modals.chunk.title')}
<img className="filter dark:invert" src={Exit} /> labelBgClassName="bg-white dark:bg-charleston-green-2"
</button> />
<div className="p-6">
<h2 className="px-3 text-xl font-semibold text-jet dark:text-bright-gray">
Add Chunk
</h2>
<div className="relative mt-6 px-3">
<span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
Title
</span>
<Input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
borderVariant="thin"
placeholder={'Enter title'}
labelBgClassName="bg-white dark:bg-charleston-green-2"
></Input>
</div>
<div className="relative mt-6 px-3">
<div className="rounded-lg border border-silver pb-1 pt-3 dark:border-silver/40">
<span className="absolute -top-2 left-5 rounded-lg bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
Body text
</span>
<textarea
id="chunk-body-text"
className="h-60 w-full px-3 outline-none dark:bg-transparent dark:text-white"
value={chunkText}
onChange={(e) => setChunkText(e.target.value)}
aria-label="Prompt Text"
></textarea>
</div>
</div>
<div className="mt-8 flex flex-row-reverse gap-1 px-3">
<button
onClick={() => {
handleSubmit(title, chunkText);
setModalState('INACTIVE');
}}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
>
Add
</button>
<button
onClick={() => {
setModalState('INACTIVE');
}}
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
</button>
</div>
</div>
</div>
</article>
</div> </div>
); <div className="relative mt-6 px-3">
} else { <div className="rounded-lg border border-silver pb-1 pt-3 dark:border-silver/40">
return ( <span className="absolute -top-2 left-5 rounded-lg bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
<div {t('modals.chunk.bodyText')}
className={`${ </span>
modalState === 'ACTIVE' ? 'visible' : 'hidden' <textarea
} fixed left-0 top-0 z-30 flex h-screen w-screen items-center justify-center bg-gray-alpha`} id="chunk-body-text"
> className="h-60 max-h-60 w-full resize-none px-3 outline-none dark:bg-transparent dark:text-white"
<article className="flex w-11/12 flex-col gap-4 rounded-2xl bg-white shadow-lg dark:bg-[#26272E] sm:w-[620px]"> value={chunkText}
<div className="relative"> onChange={(e) => setChunkText(e.target.value)}
aria-label={t('modals.chunk.promptText')}
></textarea>
</div>
</div>
{type === 'ADD' ? (
<div className="mt-8 flex flex-row-reverse gap-1 px-3">
<button
onClick={() => {
handleSubmit(title, chunkText);
setModalState('INACTIVE');
}}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
>
{t('modals.chunk.add')}
</button>
<button
onClick={() => {
setModalState('INACTIVE');
}}
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"
>
{t('modals.chunk.close')}
</button>
</div>
) : (
<div className="mt-8 flex w-full items-center justify-between px-3">
<button
className="text-nowrap rounded-full border border-solid border-red-500 px-5 py-2 text-sm text-red-500 hover:bg-red-500 hover:text-white"
onClick={() => {
setDeleteModal('ACTIVE');
}}
>
{t('modals.chunk.delete')}
</button>
<div className="flex flex-row-reverse gap-1">
<button
onClick={() => {
handleSubmit(title, chunkText);
setModalState('INACTIVE');
}}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
>
{t('modals.chunk.update')}
</button>
<button <button
className="absolute right-4 top-3 m-2 w-3"
onClick={() => { onClick={() => {
setModalState('INACTIVE'); setModalState('INACTIVE');
}} }}
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"
> >
<img className="filter dark:invert" src={Exit} /> {t('modals.chunk.close')}
</button> </button>
<div className="p-6">
<h2 className="px-3 text-xl font-semibold text-jet dark:text-bright-gray">
Edit Chunk
</h2>
<div className="relative mt-6 px-3">
<Input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
borderVariant="thin"
placeholder={'Enter title'}
labelBgClassName="bg-white dark:bg-charleston-green-2"
></Input>
</div>
<div className="relative mt-6 px-3">
<div className="rounded-lg border border-silver pb-1 pt-3 dark:border-silver/40">
<span className="absolute -top-2 left-5 rounded-lg bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
Body text
</span>
<textarea
id="chunk-body-text"
className="h-60 w-full px-3 outline-none dark:bg-transparent dark:text-white"
value={chunkText}
onChange={(e) => setChunkText(e.target.value)}
aria-label="Prompt Text"
></textarea>
</div>
</div>
<div className="mt-8 flex w-full items-center justify-between px-3">
<button
className="text-nowrap rounded-full border border-solid border-red-500 px-5 py-2 text-sm text-red-500 hover:bg-red-500 hover:text-white"
onClick={() => {
setDeleteModal('ACTIVE');
}}
>
Delete
</button>
<div className="flex flex-row-reverse gap-1">
<button
onClick={() => {
handleSubmit(title, chunkText);
setModalState('INACTIVE');
}}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
>
Update
</button>
<button
onClick={() => {
setModalState('INACTIVE');
}}
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
</button>
</div>
</div>
</div>
</div> </div>
</article> </div>
)}
</div>
);
return (
<>
<WrapperModal
close={() => setModalState('INACTIVE')}
className="sm:w-[620px]"
>
{content}
</WrapperModal>
{type === 'EDIT' && (
<ConfirmationModal <ConfirmationModal
message="Are you sure you want to delete this chunk?" message={t('modals.chunk.deleteConfirmation')}
modalState={deleteModal} modalState={deleteModal}
setModalState={setDeleteModal} setModalState={setDeleteModal}
handleSubmit={ handleSubmit={
@@ -190,9 +140,9 @@ export default function ChunkModal({
/* no-op */ /* no-op */
} }
} }
submitLabel="Delete" submitLabel={t('modals.chunk.delete')}
/> />
</div> )}
); </>
} );
} }

View File

@@ -51,7 +51,7 @@ function AddPrompt({
</label> </label>
<textarea <textarea
id="new-prompt-content" id="new-prompt-content"
className="h-56 w-full rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white" className="h-56 w-full resize-none rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
value={newPromptContent} value={newPromptContent}
onChange={(e) => setNewPromptContent(e.target.value)} onChange={(e) => setNewPromptContent(e.target.value)}
aria-label="Prompt Text" aria-label="Prompt Text"
@@ -123,7 +123,7 @@ function EditPrompt({
</label> </label>
<textarea <textarea
id="edit-prompt-content" id="edit-prompt-content"
className="h-56 w-full rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white" className="h-56 w-full resize-none rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
value={editPromptContent} value={editPromptContent}
onChange={(e) => setEditPromptContent(e.target.value)} onChange={(e) => setEditPromptContent(e.target.value)}
aria-label="Prompt Text" aria-label="Prompt Text"

View File

@@ -450,7 +450,7 @@ export default function Documents({
options={getActionOptions(index, document)} options={getActionOptions(index, document)}
anchorRef={getMenuRef(docId)} anchorRef={getMenuRef(docId)}
position="bottom-left" position="bottom-left"
offset={{ x: 48, y: -24 }} offset={{ x: 48, y: 0 }}
className="z-50" className="z-50"
/> />
</div> </div>

View File

@@ -169,13 +169,13 @@ export default function ToolConfig({
> >
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" /> <img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button> </button>
<p className="mt-px">Back to all tools</p> <p className="mt-px">{t('settings.tools.backToAllTools')}</p>
</div> </div>
<button <button
className="text-nowrap rounded-full bg-purple-30 px-3 py-2 text-xs text-white hover:bg-violets-are-blue sm:px-4 sm:py-2" className="text-nowrap rounded-full bg-purple-30 px-3 py-2 text-xs text-white hover:bg-violets-are-blue sm:px-4 sm:py-2"
onClick={handleSaveChanges} onClick={handleSaveChanges}
> >
Save {t('settings.tools.save')}
</button> </button>
</div> </div>
{/* Custom name section */} {/* Custom name section */}
@@ -282,7 +282,7 @@ export default function ToolConfig({
<Input <Input
type="text" type="text"
className="w-full" className="w-full"
placeholder="Enter description" placeholder={t('settings.tools.descriptionPlaceholder')}
value={action.description} value={action.description}
onChange={(e) => { onChange={(e) => {
setTool({ setTool({
@@ -305,11 +305,11 @@ export default function ToolConfig({
<table className="table-default"> <table className="table-default">
<thead> <thead>
<tr> <tr>
<th>Field Name</th> <th>{t('settings.tools.fieldName')}</th>
<th>Field Type</th> <th>{t('settings.tools.fieldType')}</th>
<th>Filled by LLM</th> <th>{t('settings.tools.filledByLLM')}</th>
<th>FIeld description</th> <th>{t('settings.tools.fieldDescription')}</th>
<th>Value</th> <th>{t('settings.tools.value')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -619,7 +619,7 @@ function APIToolConfig({
<div className="mt-4 px-5 py-2"> <div className="mt-4 px-5 py-2">
<div className="relative w-full"> <div className="relative w-full">
<span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-raisin-black dark:text-silver"> <span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-raisin-black dark:text-silver">
Method {t('settings.tools.method')}
</span> </span>
<Dropdown <Dropdown
options={['GET', 'POST', 'PUT', 'DELETE']} options={['GET', 'POST', 'PUT', 'DELETE']}
@@ -984,7 +984,7 @@ function APIActionTable({
handleAddProperty(); handleAddProperty();
} }
}} }}
placeholder="New property key" placeholder={t('settings.tools.propertyName')}
className="flex w-full min-w-[130.5px] items-start rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40" className="flex w-full min-w-[130.5px] items-start rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40"
/> />
</td> </td>
@@ -993,15 +993,13 @@ function APIActionTable({
onClick={handleAddProperty} onClick={handleAddProperty}
className="mr-1 rounded-full bg-purple-30 px-5 py-[4px] text-sm text-white hover:bg-violets-are-blue" className="mr-1 rounded-full bg-purple-30 px-5 py-[4px] text-sm text-white hover:bg-violets-are-blue"
> >
{' '} {t('settings.tools.add')}
Add{' '}
</button> </button>
<button <button
onClick={handleAddPropertyCancel} onClick={handleAddPropertyCancel}
className="rounded-full border border-solid border-red-500 px-5 py-[4px] text-sm text-red-500 hover:bg-red-500 hover:text-white" className="rounded-full border border-solid border-red-500 px-5 py-[4px] text-sm text-red-500 hover:bg-red-500 hover:text-white"
> >
{' '} {t('settings.tools.cancel')}
Cancel{' '}
</button> </button>
</td> </td>
<td <td
@@ -1020,7 +1018,7 @@ function APIActionTable({
onClick={() => handleAddPropertyStart(section)} onClick={() => handleAddPropertyStart(section)}
className="flex items-start text-nowrap rounded-full border border-solid border-violets-are-blue px-5 py-[4px] text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white" className="flex items-start text-nowrap rounded-full border border-solid border-violets-are-blue px-5 py-[4px] text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white"
> >
Add New Field {t('settings.tools.addNew')}
</button> </button>
</td> </td>
<td <td