import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useDropzone } from 'react-dropzone'; 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'; import Input from '../components/Input'; import { ActiveState, Doc } from '../models/misc'; import { getDocs } from '../preferences/preferenceApi'; import { setSelectedDocs, setSourceDocs, selectSourceDocs, } from '../preferences/preferenceSlice'; import WrapperModal from '../modals/WrapperModal'; function Upload({ setModalState, isOnboarding, close, }: { setModalState: (state: ActiveState) => void; isOnboarding: boolean; close: () => void; }) { const [docName, setDocName] = useState(''); const [urlName, setUrlName] = useState(''); const [url, setUrl] = useState(''); const [repoUrl, setRepoUrl] = useState(''); // P3f93 const [redditData, setRedditData] = useState({ client_id: '', client_secret: '', user_agent: '', search_queries: [''], number_posts: 10, }); const [activeTab, setActiveTab] = useState(null); const [files, setfiles] = useState([]); const [progress, setProgress] = useState<{ type: 'UPLOAD' | 'TRAINING'; percentage: number; taskId?: string; failed?: boolean; }>(); const { t } = useTranslation(); const setTimeoutRef = useRef(); 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 ]; const [urlType, setUrlType] = useState<{ label: string; value: string }>({ label: 'Crawler', value: 'crawler', }); const sourceDocs = useSelector(selectSourceDocs); useEffect(() => { if (setTimeoutRef.current) { clearTimeout(setTimeoutRef.current); } }, []); function ProgressBar({ progressPercent }: { progressPercent: number }) { return (
{progressPercent}%
); } function Progress({ title, isCancellable = false, isFailed = false, isTraining = false, }: { title: string; isCancellable?: boolean; isFailed?: boolean; isTraining?: boolean; }) { return (

{isTraining && (progress?.percentage === 100 ? 'Training completed' : title)} {!isTraining && title}

This may take several minutes

Over the token limit, please consider uploading smaller document

{/*

{progress?.percentage || 0}%

*/} {isTraining && (progress?.percentage === 100 ? ( ) : ( ))}
); } function UploadProgress() { return ; } function TrainingProgress() { const dispatch = useDispatch(); useEffect(() => { let timeoutID: number | undefined; if ((progress?.percentage ?? 0) < 100) { timeoutID = setTimeout(() => { userService .getTaskStatus(progress?.taskId as string) .then((data) => data.json()) .then((data) => { if (data.status == 'SUCCESS') { if (data.result.limited === true) { getDocs().then((data) => { dispatch(setSourceDocs(data)); dispatch( setSelectedDocs( Array.isArray(data) && data?.find( (d: Doc) => d.type?.toLowerCase() === 'local', ), ), ); }); setProgress( (progress) => progress && { ...progress, percentage: 100, failed: true, }, ); } else { getDocs().then((data) => { dispatch(setSourceDocs(data)); const docIds = new Set( (Array.isArray(sourceDocs) && sourceDocs?.map((doc: Doc) => doc.id ? doc.id : null, )) || [], ); if (data && Array.isArray(data)) { data.map((updatedDoc: Doc) => { if (updatedDoc.id && !docIds.has(updatedDoc.id)) { // Select the doc not present in the intersection of current Docs and fetched data dispatch(setSelectedDocs(updatedDoc)); return; } }); } }); setProgress( (progress) => progress && { ...progress, percentage: 100, failed: false, }, ); setDocName(''); setfiles([]); setProgress(undefined); setModalState('INACTIVE'); } } else if (data.status == 'PROGRESS') { setProgress( (progress) => progress && { ...progress, percentage: data.result.current, }, ); } }); }, 5000); } // cleanup return () => { if (timeoutID !== undefined) { clearTimeout(timeoutID); } }; }, [progress, dispatch]); return ( ); } const onDrop = useCallback((acceptedFiles: File[]) => { setfiles(acceptedFiles); setDocName(acceptedFiles[0]?.name); }, []); const doNothing = () => undefined; const uploadFile = () => { const formData = new FormData(); files.forEach((file) => { formData.append('file', file); }); formData.append('name', docName); formData.append('user', 'local'); const apiHost = import.meta.env.VITE_API_HOST; const xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', (event) => { const progress = +((event.loaded / event.total) * 100).toFixed(2); setProgress({ type: 'UPLOAD', percentage: progress }); }); xhr.onload = () => { const { task_id } = JSON.parse(xhr.responseText); setTimeoutRef.current = setTimeout(() => { setProgress({ type: 'TRAINING', percentage: 0, taskId: task_id }); }, 3000); }; xhr.open('POST', `${apiHost + '/api/upload'}`); xhr.send(formData); }; const uploadRemote = () => { const formData = new FormData(); formData.append('name', urlName); formData.append('user', 'local'); if (urlType !== null) { formData.append('source', urlType?.value); } formData.append('data', url); if ( redditData.client_id.length > 0 && redditData.client_secret.length > 0 ) { formData.set('name', 'other'); formData.set('data', JSON.stringify(redditData)); } if (urlType.value === 'github') { formData.append('repo_url', repoUrl); // Pdeac } const apiHost = import.meta.env.VITE_API_HOST; const xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', (event) => { const progress = +((event.loaded / event.total) * 100).toFixed(2); setProgress({ type: 'UPLOAD', percentage: progress }); }); xhr.onload = () => { const { task_id } = JSON.parse(xhr.responseText); setTimeoutRef.current = setTimeout(() => { setProgress({ type: 'TRAINING', percentage: 0, taskId: task_id }); }, 3000); }; xhr.open('POST', `${apiHost + '/api/remote'}`); xhr.send(formData); }; const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, multiple: true, onDragEnter: doNothing, onDragOver: doNothing, onDragLeave: doNothing, maxSize: 25000000, accept: { 'application/pdf': ['.pdf'], 'text/plain': ['.txt'], 'text/x-rst': ['.rst'], 'text/x-markdown': ['.md'], 'application/zip': ['.zip'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'], 'application/json': ['.json'], 'text/csv': ['.csv'], 'text/html': ['.html'], 'application/epub+zip': ['.epub'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': [ '.xlsx', ], 'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['.pptx'], }, }); const handleChange = ( e: React.ChangeEvent, ) => { const { name, value } = e.target; if (name === 'search_queries' && value.length > 0) { setRedditData({ ...redditData, [name]: value.split(',').map((item) => item.trim()), }); } else setRedditData({ ...redditData, [name]: name === 'number_posts' ? parseInt(value) : value, }); }; let view; if (progress?.type === 'UPLOAD') { view = ; } else if (progress?.type === 'TRAINING') { view = ; } else { view = (

{t('modals.uploadDoc.label')}

{!activeTab && (

{t('modals.uploadDoc.select')}

)} {activeTab === 'file' && ( <> setDocName(e.target.value)} borderVariant="thin" >
{t('modals.uploadDoc.name')}
{t('modals.uploadDoc.choose')}

{t('modals.uploadDoc.info')}

{t('modals.uploadDoc.uploadedFiles')}

{files.map((file) => (

{file.name}

))} {files.length === 0 && (

{t('none')}

)}
)} {activeTab === 'remote' && ( <> setUrlType(value) } size="w-full" rounded="3xl" /> {urlType.label !== 'Reddit' && urlType.label !== 'GitHub' ? ( <> setUrlName(e.target.value)} borderVariant="thin" >
{t('modals.uploadDoc.name')}
setUrl(e.target.value)} borderVariant="thin" >
{t('modals.uploadDoc.link')}
) : urlType.label === 'GitHub' ? ( // P3f93 <> setUrlName(e.target.value)} borderVariant="thin" >
{t('modals.uploadDoc.name')}
setRepoUrl(e.target.value)} borderVariant="thin" >
{t('modals.uploadDoc.repoUrl')}
) : (
{t('modals.uploadDoc.reddit.id')}
{t('modals.uploadDoc.reddit.secret')}
{t('modals.uploadDoc.reddit.agent')}
{t('modals.uploadDoc.reddit.searchQueries')}
{t('modals.uploadDoc.reddit.numberOfPosts')}
)} )} {activeTab && (
{activeTab === 'file' ? ( ) : ( )}
)}
); } return ( { close(); setDocName(''); setfiles([]); setModalState('INACTIVE'); setActiveTab(null); }} > {view} ); } export default Upload;