mirror of
https://github.com/arc53/DocsGPT
synced 2024-11-19 21:25:39 +00:00
feat(i18n): modals, Hero, Nav
This commit is contained in:
parent
4fcc80719e
commit
99952a393f
@ -1,28 +1,15 @@
|
|||||||
import DocsGPT3 from './assets/cute_docsgpt3.svg';
|
import DocsGPT3 from './assets/cute_docsgpt3.svg';
|
||||||
const demos: { header: string; query: string }[] = [
|
import { useTranslation } from 'react-i18next';
|
||||||
{
|
|
||||||
header: 'Learn about DocsGPT',
|
|
||||||
query: 'What is DocsGPT?',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: 'Summarise documentation',
|
|
||||||
query: 'Summarise current context',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: 'Write Code',
|
|
||||||
query: 'Write code for api request to /api/answer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: 'Learning Assistance',
|
|
||||||
query: 'Write potential questions for context',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Hero({
|
export default function Hero({
|
||||||
handleQuestion,
|
handleQuestion,
|
||||||
}: {
|
}: {
|
||||||
handleQuestion: (question: string) => void;
|
handleQuestion: (question: string) => void;
|
||||||
}) {
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const demos = t('demo', { returnObjects: true }) as Array<{
|
||||||
|
header: string;
|
||||||
|
query: string;
|
||||||
|
}>;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`mt-14 mb-4 flex w-full flex-col justify-end text-black-1000 dark:text-bright-gray sm:w-full lg:mt-6`}
|
className={`mt-14 mb-4 flex w-full flex-col justify-end text-black-1000 dark:text-bright-gray sm:w-full lg:mt-6`}
|
||||||
@ -36,7 +23,10 @@ export default function Hero({
|
|||||||
<div className="mb-4 flex flex-col items-center justify-center dark:text-white"></div>
|
<div className="mb-4 flex flex-col items-center justify-center dark:text-white"></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid w-full grid-cols-1 items-center gap-4 self-center text-xs sm:w-auto sm:gap-6 md:text-sm lg:grid-cols-2">
|
<div className="grid w-full grid-cols-1 items-center gap-4 self-center text-xs sm:w-auto sm:gap-6 md:text-sm lg:grid-cols-2">
|
||||||
{demos.map((demo) => (
|
{demos?.map(
|
||||||
|
(demo: { header: string; query: string }) =>
|
||||||
|
demo.header &&
|
||||||
|
demo.query && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleQuestion(demo.query)}
|
onClick={() => handleQuestion(demo.query)}
|
||||||
@ -48,7 +38,8 @@ export default function Hero({
|
|||||||
<span className="text-gray-400">{demo.query}</span>
|
<span className="text-gray-400">{demo.query}</span>
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -39,7 +39,7 @@ import SelectDocsModal from './preferences/SelectDocsModal';
|
|||||||
import ConversationTile from './conversation/ConversationTile';
|
import ConversationTile from './conversation/ConversationTile';
|
||||||
import { useDarkTheme } from './hooks';
|
import { useDarkTheme } from './hooks';
|
||||||
import SourceDropdown from './components/SourceDropdown';
|
import SourceDropdown from './components/SourceDropdown';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
interface NavigationProps {
|
interface NavigationProps {
|
||||||
navOpen: boolean;
|
navOpen: boolean;
|
||||||
setNavOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setNavOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
@ -70,6 +70,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
|||||||
const { isMobile } = useMediaQuery();
|
const { isMobile } = useMediaQuery();
|
||||||
const [isDarkTheme] = useDarkTheme();
|
const [isDarkTheme] = useDarkTheme();
|
||||||
const [isDocsListOpen, setIsDocsListOpen] = useState(false);
|
const [isDocsListOpen, setIsDocsListOpen] = useState(false);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isApiKeySet = useSelector(selectApiKeyStatus);
|
const isApiKeySet = useSelector(selectApiKeyStatus);
|
||||||
const [apiKeyModalState, setApiKeyModalState] =
|
const [apiKeyModalState, setApiKeyModalState] =
|
||||||
@ -265,14 +266,14 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
|||||||
className="opacity-80 group-hover:opacity-100"
|
className="opacity-80 group-hover:opacity-100"
|
||||||
/>
|
/>
|
||||||
<p className=" text-sm text-dove-gray group-hover:text-neutral-600 dark:text-chinese-silver dark:group-hover:text-bright-gray">
|
<p className=" text-sm text-dove-gray group-hover:text-neutral-600 dark:text-chinese-silver dark:group-hover:text-bright-gray">
|
||||||
New Chat
|
{t('newChat')}
|
||||||
</p>
|
</p>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<div className="mb-auto h-[78vh] overflow-y-auto overflow-x-hidden dark:text-white">
|
<div className="mb-auto h-[78vh] overflow-y-auto overflow-x-hidden dark:text-white">
|
||||||
{conversations && conversations.length > 0 ? (
|
{conversations && conversations.length > 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<div className=" my-auto mx-4 mt-2 flex h-6 items-center justify-between gap-4 rounded-3xl">
|
<div className=" my-auto mx-4 mt-2 flex h-6 items-center justify-between gap-4 rounded-3xl">
|
||||||
<p className="mt-1 ml-4 text-sm font-semibold">Chats</p>
|
<p className="mt-1 ml-4 text-sm font-semibold">{t('chats')}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="conversations-container">
|
<div className="conversations-container">
|
||||||
{conversations?.map((conversation) => (
|
{conversations?.map((conversation) => (
|
||||||
@ -310,7 +311,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
|||||||
onClick={() => setUploadModalState('ACTIVE')}
|
onClick={() => setUploadModalState('ACTIVE')}
|
||||||
></img>
|
></img>
|
||||||
</div>
|
</div>
|
||||||
<p className="ml-5 mt-3 text-sm font-semibold">Source Docs</p>
|
<p className="ml-5 mt-3 text-sm font-semibold">{t('sourceDocs')}</p>
|
||||||
</div>
|
</div>
|
||||||
<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
|
||||||
@ -327,7 +328,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
|||||||
className="ml-2 w-5 filter dark:invert"
|
className="ml-2 w-5 filter dark:invert"
|
||||||
/>
|
/>
|
||||||
<p className="my-auto text-sm text-eerie-black dark:text-white">
|
<p className="my-auto text-sm text-eerie-black dark:text-white">
|
||||||
Settings
|
{t('settings.label')}
|
||||||
</p>
|
</p>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
@ -345,7 +346,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
|||||||
alt="icon"
|
alt="icon"
|
||||||
className="ml-2 w-5 filter dark:invert"
|
className="ml-2 w-5 filter dark:invert"
|
||||||
/>
|
/>
|
||||||
<p className="my-auto mr-2 text-sm">About</p>
|
<p className="my-auto pr-1 text-sm">{t('about')}</p>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<div className="flex items-center justify-evenly gap-1 px-1">
|
<div className="flex items-center justify-evenly gap-1 px-1">
|
||||||
<NavLink
|
<NavLink
|
||||||
|
@ -2,7 +2,7 @@ import Trash from '../assets/trash.svg';
|
|||||||
import Arrow2 from '../assets/dropdown-arrow.svg';
|
import Arrow2 from '../assets/dropdown-arrow.svg';
|
||||||
import { Doc } from '../preferences/preferenceApi';
|
import { Doc } from '../preferences/preferenceApi';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
type Props = {
|
type Props = {
|
||||||
options: Doc[] | null;
|
options: Doc[] | null;
|
||||||
selectedDocs: Doc | null;
|
selectedDocs: Doc | null;
|
||||||
@ -30,6 +30,8 @@ function SourceDropdown({
|
|||||||
setIsDocsListOpen(false);
|
setIsDocsListOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-5/6 rounded-3xl">
|
<div className="relative w-5/6 rounded-3xl">
|
||||||
<button
|
<button
|
||||||
@ -104,7 +106,7 @@ function SourceDropdown({
|
|||||||
onClick={handleEmptyDocumentSelect}
|
onClick={handleEmptyDocumentSelect}
|
||||||
>
|
>
|
||||||
<span className="ml-4 flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap py-3">
|
<span className="ml-4 flex-1 overflow-hidden overflow-ellipsis whitespace-nowrap py-3">
|
||||||
None
|
{t('none')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +17,7 @@ import Spinner from './../assets/spinner.svg';
|
|||||||
import SpinnerDark from './../assets/spinner-dark.svg';
|
import SpinnerDark from './../assets/spinner-dark.svg';
|
||||||
import { FEEDBACK, Query } from './conversationModels';
|
import { FEEDBACK, Query } from './conversationModels';
|
||||||
import { sendFeedback } from './conversationApi';
|
import { sendFeedback } from './conversationApi';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import ArrowDown from './../assets/arrow-down.svg';
|
import ArrowDown from './../assets/arrow-down.svg';
|
||||||
export default function Conversation() {
|
export default function Conversation() {
|
||||||
const queries = useSelector(selectQueries);
|
const queries = useSelector(selectQueries);
|
||||||
@ -28,6 +29,7 @@ export default function Conversation() {
|
|||||||
const [hasScrolledToLast, setHasScrolledToLast] = useState(true);
|
const [hasScrolledToLast, setHasScrolledToLast] = useState(true);
|
||||||
const fetchStream = useRef<any>(null);
|
const fetchStream = useRef<any>(null);
|
||||||
const [eventInterrupt, setEventInterrupt] = useState(false);
|
const [eventInterrupt, setEventInterrupt] = useState(false);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleUserInterruption = () => {
|
const handleUserInterruption = () => {
|
||||||
if (!eventInterrupt && status === 'loading') setEventInterrupt(true);
|
if (!eventInterrupt && status === 'loading') setEventInterrupt(true);
|
||||||
@ -177,7 +179,7 @@ export default function Conversation() {
|
|||||||
id="inputbox"
|
id="inputbox"
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
placeholder="Type your message here..."
|
placeholder={t('inputPlaceholder')}
|
||||||
contentEditable
|
contentEditable
|
||||||
onPaste={handlePaste}
|
onPaste={handlePaste}
|
||||||
className={`max-h-24 min-h-[3.8rem] w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap rounded-full bg-white py-2 pl-4 pr-9 text-base leading-10 opacity-100 focus:outline-none dark:bg-raisin-black dark:text-bright-gray`}
|
className={`max-h-24 min-h-[3.8rem] w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap rounded-full bg-white py-2 pl-4 pr-9 text-base leading-10 opacity-100 focus:outline-none dark:bg-raisin-black dark:text-bright-gray`}
|
||||||
@ -212,7 +214,7 @@ export default function Conversation() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-gray-595959 hidden w-[100vw] self-center bg-white bg-transparent p-5 text-center text-xs dark:bg-raisin-black dark:text-bright-gray md:inline md:w-full">
|
<p className="text-gray-595959 hidden w-[100vw] self-center bg-white bg-transparent p-5 text-center text-xs dark:bg-raisin-black dark:text-bright-gray md:inline md:w-full">
|
||||||
DocsGPT uses GenAI, please review critial information using sources.
|
{t('tagline')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,25 @@
|
|||||||
"inputPlaceholder": "Type your message here...",
|
"inputPlaceholder": "Type your message here...",
|
||||||
"tagline": "DocsGPT uses GenAI, please review critial information using sources.",
|
"tagline": "DocsGPT uses GenAI, please review critial information using sources.",
|
||||||
"sourceDocs": "Source Docs",
|
"sourceDocs": "Source Docs",
|
||||||
|
"none":"None",
|
||||||
|
"demo":[
|
||||||
|
{
|
||||||
|
"header": "Learn about DocsGPT",
|
||||||
|
"query": "What is DocsGPT?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "Summarise documentation",
|
||||||
|
"query": "Summarise current context"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "Write Code",
|
||||||
|
"query": "Write code for api request to /api/answer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "Learning Assistance",
|
||||||
|
"query": "Write potential questions for context"
|
||||||
|
}
|
||||||
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"label": "Settings",
|
"label": "Settings",
|
||||||
"general": {
|
"general": {
|
||||||
@ -35,5 +54,46 @@
|
|||||||
"sourceDoc": "Source Document",
|
"sourceDoc": "Source Document",
|
||||||
"createNew": "Create New"
|
"createNew": "Create New"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"modals":{
|
||||||
|
"uploadDoc":{
|
||||||
|
"label":"Upload New Documentation",
|
||||||
|
"file":"From File",
|
||||||
|
"remote":"Remote",
|
||||||
|
"name":"Name",
|
||||||
|
"choose":"Choose Files",
|
||||||
|
"info":"Please upload .pdf, .txt, .rst, .docx, .md, .zip limited to 25mb",
|
||||||
|
"uploadedFiles":"Uploaded Files",
|
||||||
|
"cancel":"Cancel",
|
||||||
|
"train":"Train",
|
||||||
|
"link":"Link",
|
||||||
|
"urlLink":"URL Link",
|
||||||
|
"reddit":{
|
||||||
|
"id":"Client ID",
|
||||||
|
"secret":"Client Secret",
|
||||||
|
"agent":"User agent",
|
||||||
|
"searchQueries":"Search queries",
|
||||||
|
"numberOfPosts":"Number of posts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"createAPIKey":{
|
||||||
|
"label":"Create New API Key",
|
||||||
|
"apiKeyName":"API Key Name",
|
||||||
|
"chunks":"Chunks processed per query",
|
||||||
|
"prompt":"Select active prompt",
|
||||||
|
"sourceDoc":"Source document",
|
||||||
|
"create":"Create"
|
||||||
|
},
|
||||||
|
"saveKey":{
|
||||||
|
"note":"Please save your Key",
|
||||||
|
"disclaimer":"This is the only time your key will be shown.",
|
||||||
|
"copy":"Copy",
|
||||||
|
"copied":"Copied",
|
||||||
|
"confirm":"I saved the Key"
|
||||||
|
},
|
||||||
|
"deleteConv":{
|
||||||
|
"confirm":"Are you sure you want to delete all the conversations?",
|
||||||
|
"delete":"Delete"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,25 @@
|
|||||||
"inputPlaceholder": "Escribe tu mensaje aquí...",
|
"inputPlaceholder": "Escribe tu mensaje aquí...",
|
||||||
"tagline": "DocsGPT utiliza GenAI, por favor revisa información crítica utilizando fuentes.",
|
"tagline": "DocsGPT utiliza GenAI, por favor revisa información crítica utilizando fuentes.",
|
||||||
"sourceDocs": "Documentos Fuente",
|
"sourceDocs": "Documentos Fuente",
|
||||||
|
"none": "Nada",
|
||||||
|
"demo": [
|
||||||
|
{
|
||||||
|
"header": "Aprende sobre DocsGPT",
|
||||||
|
"query": "¿Qué es DocsGPT?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "Resumir documentación",
|
||||||
|
"query": "Resumir contexto actual"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "Escribir Código",
|
||||||
|
"query": "Escribir código para solicitud de API a /api/answer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "Asistencia de Aprendizaje",
|
||||||
|
"query": "Escribe posibles preguntas para el contexto"
|
||||||
|
}
|
||||||
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"label": "Configuración",
|
"label": "Configuración",
|
||||||
"general": {
|
"general": {
|
||||||
@ -35,5 +54,42 @@
|
|||||||
"sourceDoc": "Documento Fuente",
|
"sourceDoc": "Documento Fuente",
|
||||||
"createNew": "Crear Nuevo"
|
"createNew": "Crear Nuevo"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"modals": {
|
||||||
|
"uploadDoc": {
|
||||||
|
"label": "Subir Nueva Documentación",
|
||||||
|
"file": "Desde Archivo",
|
||||||
|
"remote": "Remota",
|
||||||
|
"name": "Nombre",
|
||||||
|
"choose": "Seleccionar Archivos",
|
||||||
|
"info": "Por favor, suba archivos .pdf, .txt, .rst, .docx, .md, .zip limitados a 25 MB",
|
||||||
|
"uploadedFiles": "Archivos Subidos",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"train": "Entrenar",
|
||||||
|
"link": "Enlace",
|
||||||
|
"urlLink": "Enlace URL",
|
||||||
|
"reddit": {
|
||||||
|
"id": "ID de Cliente",
|
||||||
|
"secret": "Secreto de Cliente",
|
||||||
|
"agent": "Agente de Usuario",
|
||||||
|
"searchQueries": "Consultas de Búsqueda",
|
||||||
|
"numberOfPosts": "Número de publicaciones"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"createAPIKey": {
|
||||||
|
"label": "Crear Nueva Clave de API",
|
||||||
|
"apiKeyName": "Nombre de la Clave de API",
|
||||||
|
"chunks": "Fragmentos procesados por consulta",
|
||||||
|
"prompt": "Seleccione el prompt activo",
|
||||||
|
"sourceDoc": "Documento Fuente",
|
||||||
|
"create": "Crear"
|
||||||
|
},
|
||||||
|
"saveKey": {
|
||||||
|
"note": "Por favor, guarde su Clave",
|
||||||
|
"disclaimer": "Esta es la única vez que se mostrará su clave.",
|
||||||
|
"copy": "Copiar",
|
||||||
|
"copied": "Copiado",
|
||||||
|
"confirm": "He guardado la Clave"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { useDispatch } from 'react-redux';
|
|||||||
import { ActiveState } from '../models/misc';
|
import { ActiveState } from '../models/misc';
|
||||||
import { useMediaQuery, useOutsideAlerter } from '../hooks';
|
import { useMediaQuery, useOutsideAlerter } from '../hooks';
|
||||||
import ConfirmationModal from './ConfirmationModal';
|
import ConfirmationModal from './ConfirmationModal';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Action } from '@reduxjs/toolkit';
|
import { Action } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
export default function DeleteConvModal({
|
export default function DeleteConvModal({
|
||||||
@ -18,7 +18,7 @@ export default function DeleteConvModal({
|
|||||||
const modalRef = React.useRef(null);
|
const modalRef = React.useRef(null);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { isMobile } = useMediaQuery();
|
const { isMobile } = useMediaQuery();
|
||||||
|
const { t } = useTranslation();
|
||||||
useOutsideAlerter(
|
useOutsideAlerter(
|
||||||
modalRef,
|
modalRef,
|
||||||
() => {
|
() => {
|
||||||
@ -40,10 +40,10 @@ export default function DeleteConvModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
message="Are you sure you want to delete all the conversations?"
|
message={t('modals.deleteConv.confirm')}
|
||||||
modalState={modalState}
|
modalState={modalState}
|
||||||
setModalState={setModalState}
|
setModalState={setModalState}
|
||||||
submitLabel={'Delete'}
|
submitLabel={t('modals.deleteConv.delete')}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
handleCancel={handleCancel}
|
handleCancel={handleCancel}
|
||||||
/>
|
/>
|
||||||
|
@ -221,7 +221,7 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div className="fixed top-0 left-0 z-30 flex h-screen w-screen items-center justify-center bg-gray-alpha bg-opacity-50">
|
<div className="fixed top-0 left-0 z-30 flex h-screen w-screen items-center justify-center bg-gray-alpha bg-opacity-50">
|
||||||
<div className="relative w-11/12 rounded-2xl bg-white p-10 dark:bg-outer-space sm:w-[512px]">
|
<div className="relative w-11/12 rounded-2xl bg-white p-10 dark:bg-outer-space sm:w-[512px]">
|
||||||
@ -230,12 +230,12 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
</button>
|
</button>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<span className="text-xl text-jet dark:text-bright-gray">
|
<span className="text-xl text-jet dark:text-bright-gray">
|
||||||
Create New API Key
|
{t('modals.createAPIKey.label')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative mt-5 mb-4">
|
<div className="relative mt-5 mb-4">
|
||||||
<span className="absolute left-2 -top-2 bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="absolute left-2 -top-2 bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
API Key Name
|
{t('modals.createAPIKey.apiKeyName')}
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@ -246,7 +246,7 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="my-4">
|
<div className="my-4">
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placeholder="Source document"
|
placeholder={t('modals.createAPIKey.sourceDoc')}
|
||||||
selectedValue={sourcePath}
|
selectedValue={sourcePath}
|
||||||
onSelect={(selection: { label: string; value: string }) =>
|
onSelect={(selection: { label: string; value: string }) =>
|
||||||
setSourcePath(selection)
|
setSourcePath(selection)
|
||||||
@ -260,7 +260,7 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
options={activePrompts}
|
options={activePrompts}
|
||||||
selectedValue={prompt ? prompt.name : null}
|
selectedValue={prompt ? prompt.name : null}
|
||||||
placeholder="Select active prompt"
|
placeholder={t('modals.createAPIKey.prompt')}
|
||||||
onSelect={(value: { name: string; id: string; type: string }) =>
|
onSelect={(value: { name: string; id: string; type: string }) =>
|
||||||
setPrompt(value)
|
setPrompt(value)
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="my-4">
|
<div className="my-4">
|
||||||
<p className="mb-2 ml-2 font-bold text-jet dark:text-bright-gray">
|
<p className="mb-2 ml-2 font-bold text-jet dark:text-bright-gray">
|
||||||
Chunks processed per query
|
{t('modals.createAPIKey.chunks')}
|
||||||
</p>
|
</p>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
options={chunkOptions}
|
options={chunkOptions}
|
||||||
@ -292,7 +292,7 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
}
|
}
|
||||||
className="float-right mt-4 rounded-full bg-purple-30 px-5 py-2 text-sm text-white hover:bg-[#6F3FD1] disabled:opacity-50"
|
className="float-right mt-4 rounded-full bg-purple-30 px-5 py-2 text-sm text-white hover:bg-[#6F3FD1] disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Create
|
{t('modals.createAPIKey.create')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -301,6 +301,7 @@ const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||||||
|
|
||||||
const SaveAPIKeyModal: React.FC<SaveAPIKeyModalProps> = ({ apiKey, close }) => {
|
const SaveAPIKeyModal: React.FC<SaveAPIKeyModalProps> = ({ apiKey, close }) => {
|
||||||
const [isCopied, setIsCopied] = React.useState(false);
|
const [isCopied, setIsCopied] = React.useState(false);
|
||||||
|
const { t } = useTranslation();
|
||||||
const handleCopyKey = () => {
|
const handleCopyKey = () => {
|
||||||
navigator.clipboard.writeText(apiKey);
|
navigator.clipboard.writeText(apiKey);
|
||||||
setIsCopied(true);
|
setIsCopied(true);
|
||||||
@ -311,9 +312,12 @@ const SaveAPIKeyModal: React.FC<SaveAPIKeyModalProps> = ({ apiKey, close }) => {
|
|||||||
<button className="absolute top-3 right-4 m-2 w-3" onClick={close}>
|
<button className="absolute top-3 right-4 m-2 w-3" onClick={close}>
|
||||||
<img className="filter dark:invert" src={Exit} />
|
<img className="filter dark:invert" src={Exit} />
|
||||||
</button>
|
</button>
|
||||||
<h1 className="my-0 text-xl font-medium">Please save your Key</h1>
|
<h1 className="my-0 text-xl font-medium">
|
||||||
|
{' '}
|
||||||
|
{t('modals.saveKey.note')}
|
||||||
|
</h1>
|
||||||
<h3 className="text-sm font-normal text-outer-space">
|
<h3 className="text-sm font-normal text-outer-space">
|
||||||
This is the only time your key will be shown.
|
{t('modals.saveKey.disclaimer')}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex justify-between py-2">
|
<div className="flex justify-between py-2">
|
||||||
<div>
|
<div>
|
||||||
@ -324,14 +328,14 @@ const SaveAPIKeyModal: React.FC<SaveAPIKeyModalProps> = ({ apiKey, close }) => {
|
|||||||
className="my-1 h-10 w-20 rounded-full border border-solid border-purple-30 p-2 text-sm text-purple-30 hover:bg-purple-30 hover:text-white"
|
className="my-1 h-10 w-20 rounded-full border border-solid border-purple-30 p-2 text-sm text-purple-30 hover:bg-purple-30 hover:text-white"
|
||||||
onClick={handleCopyKey}
|
onClick={handleCopyKey}
|
||||||
>
|
>
|
||||||
{isCopied ? 'Copied' : 'Copy'}
|
{isCopied ? t('modals.saveKey.copied') : t('modals.saveKey.copy')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={close}
|
onClick={close}
|
||||||
className="rounded-full bg-philippine-yellow px-4 py-3 font-medium text-black hover:bg-[#E6B91A]"
|
className="rounded-full bg-philippine-yellow px-4 py-3 font-medium text-black hover:bg-[#E6B91A]"
|
||||||
>
|
>
|
||||||
I saved the Key
|
{t('modals.saveKey.confirm')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import Prompts from './Prompts';
|
import Prompts from './Prompts';
|
||||||
import { useDarkTheme } from '../hooks';
|
import { useDarkTheme } from '../hooks';
|
||||||
@ -19,7 +19,7 @@ const General: React.FC = () => {
|
|||||||
t,
|
t,
|
||||||
i18n: { changeLanguage, language },
|
i18n: { changeLanguage, language },
|
||||||
} = useTranslation();
|
} = useTranslation();
|
||||||
const themes = [t('settings.general.light'), t('settings.general.dark')];
|
const themes = ['Light', 'Dark'];
|
||||||
|
|
||||||
const languageOptions = [
|
const languageOptions = [
|
||||||
{
|
{
|
||||||
@ -38,7 +38,7 @@ const General: React.FC = () => {
|
|||||||
const selectedChunks = useSelector(selectChunks);
|
const selectedChunks = useSelector(selectChunks);
|
||||||
const [isDarkTheme, toggleTheme] = useDarkTheme();
|
const [isDarkTheme, toggleTheme] = useDarkTheme();
|
||||||
const [selectedTheme, setSelectedTheme] = React.useState(
|
const [selectedTheme, setSelectedTheme] = React.useState(
|
||||||
isDarkTheme ? t('settings.general.dark') : t('settings.general.light'),
|
isDarkTheme ? 'Dark' : 'Light',
|
||||||
);
|
);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const locale = localStorage.getItem('docsgpt-locale');
|
const locale = localStorage.getItem('docsgpt-locale');
|
||||||
@ -46,10 +46,7 @@ const General: React.FC = () => {
|
|||||||
locale ? languageOptions.find((option) => option.value === locale) : 'en',
|
locale ? languageOptions.find((option) => option.value === locale) : 'en',
|
||||||
);
|
);
|
||||||
const selectedPrompt = useSelector(selectPrompt);
|
const selectedPrompt = useSelector(selectPrompt);
|
||||||
useEffect(() => {
|
|
||||||
console.log(selectedLanguage);
|
|
||||||
console.log(language);
|
|
||||||
}, [selectedLanguage]);
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const fetchPrompts = async () => {
|
const fetchPrompts = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -6,7 +6,7 @@ import { ActiveState } from '../models/misc';
|
|||||||
import { getDocs } from '../preferences/preferenceApi';
|
import { getDocs } from '../preferences/preferenceApi';
|
||||||
import { setSourceDocs } from '../preferences/preferenceSlice';
|
import { setSourceDocs } from '../preferences/preferenceSlice';
|
||||||
import Dropdown from '../components/Dropdown';
|
import Dropdown from '../components/Dropdown';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
export default function Upload({
|
export default function Upload({
|
||||||
modalState,
|
modalState,
|
||||||
setModalState,
|
setModalState,
|
||||||
@ -24,6 +24,7 @@ export default function Upload({
|
|||||||
search_queries: [''],
|
search_queries: [''],
|
||||||
number_posts: 10,
|
number_posts: 10,
|
||||||
});
|
});
|
||||||
|
const { t } = useTranslation();
|
||||||
const urlOptions: { label: string; value: string }[] = [
|
const urlOptions: { label: string; value: string }[] = [
|
||||||
{ label: 'Crawler', value: 'crawler' },
|
{ label: 'Crawler', value: 'crawler' },
|
||||||
// { label: 'Sitemap', value: 'sitemap' },
|
// { label: 'Sitemap', value: 'sitemap' },
|
||||||
@ -238,7 +239,7 @@ export default function Upload({
|
|||||||
view = (
|
view = (
|
||||||
<>
|
<>
|
||||||
<p className="text-xl text-jet dark:text-bright-gray">
|
<p className="text-xl text-jet dark:text-bright-gray">
|
||||||
Upload New Documentation
|
{t('modals.uploadDoc.label')}
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
@ -249,7 +250,7 @@ export default function Upload({
|
|||||||
: 'text-sonic-silver hover:text-purple-30'
|
: 'text-sonic-silver hover:text-purple-30'
|
||||||
} mr-4 rounded-full px-[20px] py-[5px] text-sm font-semibold`}
|
} mr-4 rounded-full px-[20px] py-[5px] text-sm font-semibold`}
|
||||||
>
|
>
|
||||||
From File
|
{t('modals.uploadDoc.file')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab('remote')}
|
onClick={() => setActiveTab('remote')}
|
||||||
@ -259,7 +260,7 @@ export default function Upload({
|
|||||||
: 'text-sonic-silver hover:text-purple-30'
|
: 'text-sonic-silver hover:text-purple-30'
|
||||||
} mr-4 rounded-full px-[20px] py-[5px] text-sm font-semibold`}
|
} mr-4 rounded-full px-[20px] py-[5px] text-sm font-semibold`}
|
||||||
>
|
>
|
||||||
Remote
|
{t('modals.uploadDoc.remote')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{activeTab === 'file' && (
|
{activeTab === 'file' && (
|
||||||
@ -272,21 +273,21 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Name
|
{t('modals.uploadDoc.name')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div {...getRootProps()}>
|
<div {...getRootProps()}>
|
||||||
<span 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">
|
<span 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">
|
||||||
<input type="button" {...getInputProps()} />
|
<input type="button" {...getInputProps()} />
|
||||||
Choose Files
|
{t('modals.uploadDoc.choose')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="mb-0 text-xs italic text-gray-4000">
|
<p className="mb-0 text-xs italic text-gray-4000">
|
||||||
Please upload .pdf, .txt, .rst, .docx, .md, .zip limited to 25mb
|
{t('modals.uploadDoc.info')}
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-0">
|
<div className="mt-0">
|
||||||
<p className="mb-[14px] font-medium text-eerie-black dark:text-light-gray">
|
<p className="mb-[14px] font-medium text-eerie-black dark:text-light-gray">
|
||||||
Uploaded Files
|
{t('modals.uploadDoc.uploadedFiles')}
|
||||||
</p>
|
</p>
|
||||||
{files.map((file) => (
|
{files.map((file) => (
|
||||||
<p key={file.name} className="text-gray-6000">
|
<p key={file.name} className="text-gray-6000">
|
||||||
@ -294,7 +295,9 @@ export default function Upload({
|
|||||||
</p>
|
</p>
|
||||||
))}
|
))}
|
||||||
{files.length === 0 && (
|
{files.length === 0 && (
|
||||||
<p className="text-gray-6000 dark:text-light-gray">None</p>
|
<p className="text-gray-6000 dark:text-light-gray">
|
||||||
|
{t('none')}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -313,7 +316,7 @@ export default function Upload({
|
|||||||
{urlType.label !== 'Reddit' ? (
|
{urlType.label !== 'Reddit' ? (
|
||||||
<>
|
<>
|
||||||
<input
|
<input
|
||||||
placeholder="Enter name"
|
placeholder={`Enter ${t('modals.uploadDoc.name')}`}
|
||||||
type="text"
|
type="text"
|
||||||
className="h-[42px] w-full rounded-full border-2 border-silver px-3 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
className="h-[42px] w-full rounded-full border-2 border-silver px-3 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
||||||
value={urlName}
|
value={urlName}
|
||||||
@ -321,11 +324,11 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Name
|
{t('modals.uploadDoc.name')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
placeholder="URL Link"
|
placeholder={t('modals.uploadDoc.urlLink')}
|
||||||
type="text"
|
type="text"
|
||||||
className="h-[42px] w-full rounded-full border-2 border-silver px-3 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
className="h-[42px] w-full rounded-full border-2 border-silver px-3 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
||||||
value={url}
|
value={url}
|
||||||
@ -333,7 +336,7 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Link
|
{t('modals.uploadDoc.link')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -349,7 +352,7 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Client ID
|
{t('modals.uploadDoc.reddit.id')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@ -362,7 +365,7 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Client secret
|
{t('modals.uploadDoc.reddit.secret')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@ -375,7 +378,7 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
User agent
|
{t('modals.uploadDoc.reddit.agent')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@ -388,7 +391,7 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Search queries
|
{t('modals.uploadDoc.reddit.searchQueries')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@ -401,7 +404,7 @@ export default function Upload({
|
|||||||
></input>
|
></input>
|
||||||
<div className="relative bottom-12 left-2 mt-[-20px]">
|
<div className="relative bottom-12 left-2 mt-[-20px]">
|
||||||
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
<span className="bg-white px-2 text-xs text-gray-4000 dark:bg-outer-space dark:text-silver">
|
||||||
Number of posts
|
{t('modals.uploadDoc.reddit.numberOfPosts')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -422,14 +425,14 @@ export default function Upload({
|
|||||||
activeTab === 'file'
|
activeTab === 'file'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Train
|
{t('modals.uploadDoc.train')}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={uploadRemote}
|
onClick={uploadRemote}
|
||||||
className={`ml-2 cursor-pointer rounded-3xl bg-purple-30 py-2 px-6 text-sm text-white hover:bg-[#6F3FD1]`}
|
className={`ml-2 cursor-pointer rounded-3xl bg-purple-30 py-2 px-6 text-sm text-white hover:bg-[#6F3FD1]`}
|
||||||
>
|
>
|
||||||
Train
|
{t('modals.uploadDoc.train')}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
@ -440,7 +443,7 @@ export default function Upload({
|
|||||||
}}
|
}}
|
||||||
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"
|
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"
|
||||||
>
|
>
|
||||||
Cancel
|
{t('modals.uploadDoc.cancel')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user