import React, { useState, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import ArrowLeft from './assets/arrow-left.svg'; import ArrowRight from './assets/arrow-right.svg'; import Exit from './assets/exit.svg'; import Trash from './assets/trash.svg'; import { selectPrompt, setPrompt, selectSourceDocs, setSourceDocs, setChunks, selectChunks, } from './preferences/preferenceSlice'; import { Doc } from './preferences/preferenceApi'; import { useDarkTheme } from './hooks'; import Dropdown from './components/Dropdown'; import { ActiveState } from './models/misc'; import PromptsModal from './preferences/PromptsModal'; type PromptProps = { prompts: { name: string; id: string; type: string }[]; selectedPrompt: { name: string; id: string; type: string }; onSelectPrompt: (name: string, id: string, type: string) => void; setPrompts: (prompts: { name: string; id: string; type: string }[]) => void; apiHost: string; }; const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; const embeddingsName = import.meta.env.VITE_EMBEDDINGS_NAME || 'huggingface_sentence-transformers/all-mpnet-base-v2'; const Setting: React.FC = () => { const tabs = ['General', 'Documents', 'API Keys']; const [activeTab, setActiveTab] = useState('General'); const documents = useSelector(selectSourceDocs); const dispatch = useDispatch(); const [widgetScreenshot, setWidgetScreenshot] = useState(null); const updateWidgetScreenshot = (screenshot: File | null) => { setWidgetScreenshot(screenshot); }; const handleDeleteClick = (index: number, doc: Doc) => { const docPath = 'indexes/' + 'local' + '/' + doc.name; fetch(`${apiHost}/api/delete_old?path=${docPath}`, { method: 'GET', }) .then((response) => { if (response.ok && documents) { const updatedDocuments = [ ...documents.slice(0, index), ...documents.slice(index + 1), ]; dispatch(setSourceDocs(updatedDocuments)); } }) .catch((error) => console.error(error)); }; return (

Settings

{tabs.map((tab, index) => ( ))}
{renderActiveTab()} {/* {activeTab === 'Widgets' && ( )} */}
); function scrollTabs(direction: number) { const container = document.querySelector('.flex-nowrap'); if (container) { container.scrollLeft += direction * 100; // Adjust the scroll amount as needed } } function renderActiveTab() { switch (activeTab) { case 'General': return ; case 'Documents': return ( ); case 'Widgets': return ( ); case 'API Keys': return ; default: return null; } } }; const General: React.FC = () => { const themes = ['Light', 'Dark']; const languages = ['English']; const chunks = ['0', '2', '4', '6', '8', '10']; const [prompts, setPrompts] = useState< { name: string; id: string; type: string }[] >([]); const selectedChunks = useSelector(selectChunks); const [isDarkTheme, toggleTheme] = useDarkTheme(); const [selectedTheme, setSelectedTheme] = useState( isDarkTheme ? 'Dark' : 'Light', ); const dispatch = useDispatch(); const [selectedLanguage, setSelectedLanguage] = useState(languages[0]); const selectedPrompt = useSelector(selectPrompt); const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; useEffect(() => { const fetchPrompts = async () => { try { const response = await fetch(`${apiHost}/api/get_prompts`); if (!response.ok) { throw new Error('Failed to fetch prompts'); } const promptsData = await response.json(); setPrompts(promptsData); } catch (error) { console.error(error); } }; fetchPrompts(); }, []); return (

Select Theme

{ setSelectedTheme(option); option !== selectedTheme && toggleTheme(); }} size="w-56" rounded="3xl" />

Select Language

Chunks processed per query

dispatch(setChunks(value))} size="w-56" rounded="3xl" />
dispatch(setPrompt({ name: name, id: id, type: type })) } setPrompts={setPrompts} apiHost={apiHost} />
); }; export default Setting; const Prompts: React.FC = ({ prompts, selectedPrompt, onSelectPrompt, setPrompts, }) => { const handleSelectPrompt = ({ name, id, type, }: { name: string; id: string; type: string; }) => { setEditPromptName(name); onSelectPrompt(name, id, type); }; const [newPromptName, setNewPromptName] = useState(''); const [newPromptContent, setNewPromptContent] = useState(''); const [editPromptName, setEditPromptName] = useState(''); const [editPromptContent, setEditPromptContent] = useState(''); const [currentPromptEdit, setCurrentPromptEdit] = useState({ id: '', name: '', type: '', }); const [modalType, setModalType] = useState<'ADD' | 'EDIT'>('ADD'); const [modalState, setModalState] = useState('INACTIVE'); const handleAddPrompt = async () => { try { const response = await fetch(`${apiHost}/api/create_prompt`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newPromptName, content: newPromptContent, }), }); if (!response.ok) { throw new Error('Failed to add prompt'); } const newPrompt = await response.json(); if (setPrompts) { setPrompts([ ...prompts, { name: newPromptName, id: newPrompt.id, type: 'private' }, ]); } setModalState('INACTIVE'); onSelectPrompt(newPromptName, newPrompt.id, newPromptContent); setNewPromptName(newPromptName); } catch (error) { console.error(error); } }; const handleDeletePrompt = (id: string) => { setPrompts(prompts.filter((prompt) => prompt.id !== id)); fetch(`${apiHost}/api/delete_prompt`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: id }), }) .then((response) => { if (!response.ok) { throw new Error('Failed to delete prompt'); } // get 1st prompt and set it as selected if (prompts.length > 0) { onSelectPrompt(prompts[0].name, prompts[0].id, prompts[0].type); } }) .catch((error) => { console.error(error); }); }; const fetchPromptContent = async (id: string) => { console.log('fetching prompt content'); try { const response = await fetch( `${apiHost}/api/get_single_prompt?id=${id}`, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }, ); if (!response.ok) { throw new Error('Failed to fetch prompt content'); } const promptContent = await response.json(); setEditPromptContent(promptContent.content); } catch (error) { console.error(error); } }; const handleSaveChanges = (id: string, type: string) => { fetch(`${apiHost}/api/update_prompt`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: id, name: editPromptName, content: editPromptContent, }), }) .then((response) => { if (!response.ok) { throw new Error('Failed to update prompt'); } if (setPrompts) { const existingPromptIndex = prompts.findIndex( (prompt) => prompt.id === id, ); if (existingPromptIndex === -1) { setPrompts([ ...prompts, { name: editPromptName, id: id, type: type }, ]); } else { const updatedPrompts = [...prompts]; updatedPrompts[existingPromptIndex] = { name: editPromptName, id: id, type: type, }; setPrompts(updatedPrompts); } } setModalState('INACTIVE'); onSelectPrompt(editPromptName, id, type); }) .catch((error) => { console.error(error); }); }; return ( <>

Active Prompt

{ setModalType('EDIT'); setEditPromptName(name); fetchPromptContent(id); setCurrentPromptEdit({ id: id, name: name, type: type }); setModalState('ACTIVE'); }} onDelete={handleDeletePrompt} />
); }; type AddPromptModalProps = { newPromptName: string; onNewPromptNameChange: (name: string) => void; onAddPrompt: () => void; onClose: () => void; }; const AddPromptModal: React.FC = ({ newPromptName, onNewPromptNameChange, onAddPrompt, onClose, }) => { return (

Add New Prompt

onNewPromptNameChange(e.target.value)} className="mb-4 w-full rounded-3xl border-2 p-2 dark:border-chinese-silver" />
); }; type DocumentsProps = { documents: Doc[] | null; handleDeleteDocument: (index: number, document: Doc) => void; }; const Documents: React.FC = ({ documents, handleDeleteDocument, }) => { return (
{documents && documents.map((document, index) => ( ))}
Document Name Vector Date Type
{document.name} {document.date} {document.location === 'remote' ? 'Pre-loaded' : 'Private'} {document.location !== 'remote' && ( Delete { event.stopPropagation(); handleDeleteDocument(index, document); }} /> )}
{/* */}
{/* {isAddDocumentModalOpen && ( )} */}
); }; type Document = { name: string; vectorDate: string; vectorLocation: string; }; // Modal for adding a new document type AddDocumentModalProps = { newDocument: Document; onNewDocumentChange: (document: Document) => void; onAddDocument: () => void; onClose: () => void; }; const AddDocumentModal: React.FC = ({ newDocument, onNewDocumentChange, onAddDocument, onClose, }) => { return (

Add New Document

onNewDocumentChange({ ...newDocument, name: e.target.value }) } className="mb-4 w-full rounded-lg border-2 p-2" /> onNewDocumentChange({ ...newDocument, vectorDate: e.target.value }) } className="mb-4 w-full rounded-lg border-2 p-2" /> onNewDocumentChange({ ...newDocument, vectorLocation: e.target.value, }) } className="mb-4 w-full rounded-lg border-2 p-2" />
); }; const APIKeys: React.FC = () => { const [isCreateModalOpen, setCreateModal] = useState(false); const [isSaveKeyModalOpen, setSaveKeyModal] = useState(false); const [newKey, setNewKey] = useState(''); const [apiKeys, setApiKeys] = useState< { name: string; key: string; source: string; id: string }[] >([]); const handleDeleteKey = (id: string) => { fetch(`${apiHost}/api/delete_api_key`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id }), }) .then((response) => { if (!response.ok) { throw new Error('Failed to delete API Key'); } return response.json(); }) .then((data) => { data.status === 'ok' && setApiKeys((previous) => previous.filter((elem) => elem.id !== id)); }) .catch((error) => { console.error(error); }); }; useEffect(() => { fetchAPIKeys(); }, []); const fetchAPIKeys = async () => { try { const response = await fetch(`${apiHost}/api/get_api_keys`); if (!response.ok) { throw new Error('Failed to fetch API Keys'); } const apiKeys = await response.json(); setApiKeys(apiKeys); } catch (error) { console.log(error); } }; const createAPIKey = (payload: { name: string; source: string; prompt_id: string; chunks: string; }) => { fetch(`${apiHost}/api/create_api_key`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }) .then((response) => { if (!response.ok) { throw new Error('Failed to create API Key'); } return response.json(); }) .then((data) => { setApiKeys([...apiKeys, data]); setCreateModal(false); //close the create key modal setNewKey(data.key); setSaveKeyModal(true); // render the newly created key fetchAPIKeys(); }) .catch((error) => { console.error(error); }); }; return (
{isCreateModalOpen && ( setCreateModal(false)} createAPIKey={createAPIKey} /> )} {isSaveKeyModalOpen && ( setSaveKeyModal(false)} /> )}
{apiKeys?.map((element, index) => ( ))}
Name Source document API Key
{element.name} {element.source} {element.key} Delete handleDeleteKey(element.id)} />
); }; type SaveAPIKeyModalProps = { apiKey: string; close: () => void; }; const SaveAPIKeyModal: React.FC = ({ apiKey, close }) => { const [isCopied, setIsCopied] = useState(false); const handleCopyKey = () => { navigator.clipboard.writeText(apiKey); setIsCopied(true); }; return (

Please save your Key

This is the only time your key will be shown.

API Key

{apiKey}
); }; type CreateAPIKeyModalProps = { close: () => void; createAPIKey: (payload: { name: string; source: string; prompt_id: string; chunks: string; }) => void; }; const CreateAPIKeyModal: React.FC = ({ close, createAPIKey, }) => { const [APIKeyName, setAPIKeyName] = useState(''); const [sourcePath, setSourcePath] = useState<{ label: string; value: string; } | null>(null); const chunkOptions = ['0', '2', '4', '6', '8', '10']; const [chunk, setChunk] = useState('2'); const [activePrompts, setActivePrompts] = useState< { name: string; id: string; type: string }[] >([]); const [prompt, setPrompt] = useState<{ name: string; id: string; type: string; } | null>(null); const docs = useSelector(selectSourceDocs); useEffect(() => { const fetchPrompts = async () => { try { const response = await fetch(`${apiHost}/api/get_prompts`); if (!response.ok) { throw new Error('Failed to fetch prompts'); } const promptsData = await response.json(); setActivePrompts(promptsData); } catch (error) { console.error(error); } }; fetchPrompts(); }, []); const extractDocPaths = () => docs ? docs .filter((doc) => doc.model === embeddingsName) .map((doc: Doc) => { let namePath = doc.name; if (doc.language === namePath) { namePath = '.project'; } let docPath = 'default'; if (doc.location === 'local') { docPath = 'local' + '/' + doc.name + '/'; } else if (doc.location === 'remote') { docPath = doc.language + '/' + namePath + '/' + doc.version + '/' + doc.model + '/'; } return { label: doc.name, value: docPath, }; }) : []; return (
Create New API Key
API Key Name setAPIKeyName(e.target.value)} />
setSourcePath(selection) } options={extractDocPaths()} />
setPrompt(value) } />

Chunks processed per query

setChunk(value)} />
); }; const Widgets: React.FC<{ widgetScreenshot: File | null; onWidgetScreenshotChange: (screenshot: File | null) => void; }> = ({ widgetScreenshot, onWidgetScreenshotChange }) => { const widgetSources = ['Source 1', 'Source 2', 'Source 3']; const widgetMethods = ['Method 1', 'Method 2', 'Method 3']; const widgetTypes = ['Type 1', 'Type 2', 'Type 3']; const [selectedWidgetSource, setSelectedWidgetSource] = useState( widgetSources[0], ); const [selectedWidgetMethod, setSelectedWidgetMethod] = useState( widgetMethods[0], ); const [selectedWidgetType, setSelectedWidgetType] = useState(widgetTypes[0]); // const [widgetScreenshot, setWidgetScreenshot] = useState(null); const [widgetCode, setWidgetCode] = useState(''); // Your widget code state const handleScreenshotChange = ( event: React.ChangeEvent, ) => { const files = event.target.files; if (files && files.length > 0) { const selectedScreenshot = files[0]; onWidgetScreenshotChange(selectedScreenshot); // Update the screenshot in the parent component } }; const handleCopyToClipboard = () => { // Create a new textarea element to select the text const textArea = document.createElement('textarea'); textArea.value = widgetCode; document.body.appendChild(textArea); // Select and copy the text textArea.select(); document.execCommand('copy'); // Clean up the textarea element document.body.removeChild(textArea); }; return (

Widget Source

Widget Method

Widget Type

Widget Code Snippet