Feature/Add new doc store upsert and refresh API (#3556)

add new doc store upsert and refresh API
This commit is contained in:
Henry Heng
2024-11-25 15:47:13 +00:00
committed by GitHub
parent 36496b1611
commit a2c36b4447
15 changed files with 1424 additions and 803 deletions
+7 -3
View File
@@ -14,7 +14,9 @@ const editChunkFromStore = (storeId, loaderId, chunkId, body) =>
const getFileChunks = (storeId, fileId, pageNo) => client.get(`/document-store/chunks/${storeId}/${fileId}/${pageNo}`)
const previewChunks = (body) => client.post('/document-store/loader/preview', body)
const processChunks = (body) => client.post(`/document-store/loader/process`, body)
const processLoader = (body, loaderId) => client.post(`/document-store/loader/process/${loaderId}`, body)
const saveProcessingLoader = (body) => client.post(`/document-store/loader/save`, body)
const refreshLoader = (storeId) => client.post(`/document-store/refresh/${storeId}`)
const insertIntoVectorStore = (body) => client.post(`/document-store/vectorstore/insert`, body)
const saveVectorStoreConfig = (body) => client.post(`/document-store/vectorstore/save`, body)
@@ -33,7 +35,7 @@ export default {
getFileChunks,
updateDocumentStore,
previewChunks,
processChunks,
processLoader,
getDocumentLoaders,
deleteChunkFromStore,
editChunkFromStore,
@@ -45,5 +47,7 @@ export default {
saveVectorStoreConfig,
queryVectorStore,
deleteVectorStoreDataFromStore,
updateVectorStoreConfig
updateVectorStoreConfig,
saveProcessingLoader,
refreshLoader
}
+4
View File
@@ -98,6 +98,10 @@ const MainRoutes = {
path: '/document-stores/vector/:id',
element: <VectorStoreConfigure />
},
{
path: '/document-stores/vector/:id/:docId',
element: <VectorStoreConfigure />
},
{
path: '/document-stores/query/:id',
element: <VectorStoreQuery />
@@ -60,7 +60,8 @@ const DocumentStoreCard = ({ data, images, onClick }) => {
WebkitBoxOrient: 'vertical',
textOverflow: 'ellipsis',
overflow: 'hidden',
flex: 1
flex: 1,
mr: 1
}}
>
{data.name}
@@ -35,6 +35,8 @@ import ErrorBoundary from '@/ErrorBoundary'
import { StyledButton } from '@/ui-component/button/StyledButton'
import ViewHeader from '@/layout/MainLayout/ViewHeader'
import DeleteDocStoreDialog from './DeleteDocStoreDialog'
import DocumentStoreStatus from '@/views/docstore/DocumentStoreStatus'
import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog'
// API
import documentsApi from '@/api/documentstore'
@@ -42,22 +44,18 @@ import documentsApi from '@/api/documentstore'
// Hooks
import useApi from '@/hooks/useApi'
import useNotifier from '@/utils/useNotifier'
import { getFileName } from '@/utils/genericHelper'
import useConfirm from '@/hooks/useConfirm'
// icons
import {
IconPlus,
IconRefresh,
IconListDetails,
IconTrash,
IconX,
IconVectorBezier2,
IconRowInsertTop,
IconZoomScan
} from '@tabler/icons-react'
import { IconPlus, IconRefresh, IconX, IconVectorBezier2 } from '@tabler/icons-react'
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'
import FileDeleteIcon from '@mui/icons-material/Delete'
import FileEditIcon from '@mui/icons-material/Edit'
import FileChunksIcon from '@mui/icons-material/AppRegistration'
import NoteAddIcon from '@mui/icons-material/NoteAdd'
import SearchIcon from '@mui/icons-material/Search'
import RefreshIcon from '@mui/icons-material/Refresh'
import doc_store_details_emptySVG from '@/assets/images/doc_store_details_empty.svg'
// store
@@ -127,6 +125,7 @@ const DocumentStoreDetails = () => {
const navigate = useNavigate()
const dispatch = useDispatch()
useNotifier()
const { confirm } = useConfirm()
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
@@ -144,6 +143,9 @@ const DocumentStoreDetails = () => {
const [showDeleteDocStoreDialog, setShowDeleteDocStoreDialog] = useState(false)
const [deleteDocStoreDialogProps, setDeleteDocStoreDialogProps] = useState({})
const [anchorEl, setAnchorEl] = useState(null)
const open = Boolean(anchorEl)
const URLpath = document.location.pathname.toString().split('/')
const storeId = URLpath[URLpath.length - 1] === 'document-stores' ? '' : URLpath[URLpath.length - 1]
@@ -212,9 +214,10 @@ const DocumentStoreDetails = () => {
} catch (error) {
setBackdropLoading(false)
setError(error)
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to delete loader: ${errorData}`,
message: `Failed to delete Document Store: ${
typeof error.response.data === 'object' ? error.response.data.message : error.response.data
}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -249,9 +252,10 @@ const DocumentStoreDetails = () => {
} catch (error) {
setError(error)
setBackdropLoading(false)
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to delete loader: ${errorData}`,
message: `Failed to delete Document Loader: ${
typeof error.response.data === 'object' ? error.response.data.message : error.response.data
}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -294,6 +298,55 @@ const DocumentStoreDetails = () => {
setShowDeleteDocStoreDialog(true)
}
const onStoreRefresh = async (storeId) => {
const confirmPayload = {
title: `Refresh all loaders and upsert all chunks?`,
description: `This will re-process all loaders and upsert all chunks. This action might take some time.`,
confirmButtonName: 'Refresh',
cancelButtonName: 'Cancel'
}
const isConfirmed = await confirm(confirmPayload)
if (isConfirmed) {
setAnchorEl(null)
setBackdropLoading(true)
try {
const resp = await documentsApi.refreshLoader(storeId)
if (resp.data) {
enqueueSnackbar({
message: 'Document store refresh successfully!',
options: {
key: new Date().getTime() + Math.random(),
variant: 'success',
action: (key) => (
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
<IconX />
</Button>
)
}
})
}
setBackdropLoading(false)
} catch (error) {
setBackdropLoading(false)
enqueueSnackbar({
message: `Failed to refresh document store: ${
typeof error.response.data === 'object' ? error.response.data.message : error.response.data
}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
action: (key) => (
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
<IconX />
</Button>
)
}
})
}
}
}
const onEditClicked = () => {
const data = {
name: documentStore.name,
@@ -316,6 +369,16 @@ const DocumentStoreDetails = () => {
getSpecificDocumentStore.request(storeId)
}
const handleClick = (event) => {
event.preventDefault()
event.stopPropagation()
setAnchorEl(event.currentTarget)
}
const handleClose = () => {
setAnchorEl(null)
}
useEffect(() => {
getSpecificDocumentStore.request(storeId)
@@ -358,85 +421,86 @@ const DocumentStoreDetails = () => {
onBack={() => navigate('/document-stores')}
onEdit={() => onEditClicked()}
>
<IconButton
onClick={() => onStoreDelete(documentStore.vectorStoreConfig, documentStore.recordManagerConfig)}
size='small'
color='error'
title='Delete Document Store'
sx={{ mr: 2 }}
>
<IconTrash />
</IconButton>
{(documentStore?.status === 'STALE' || documentStore?.status === 'UPSERTING') && (
<IconButton onClick={onConfirm} size='small' color='primary' title='Refresh Document Store'>
<IconRefresh />
</IconButton>
)}
<StyledButton
variant='contained'
sx={{ borderRadius: 2, height: '100%', color: 'white' }}
sx={{ ml: 2, minWidth: 200, borderRadius: 2, height: '100%', color: 'white' }}
startIcon={<IconPlus />}
onClick={listLoaders}
>
Add Document Loader
</StyledButton>
{(documentStore?.status === 'STALE' || documentStore?.status === 'UPSERTING') && (
<Button variant='outlined' sx={{ mr: 2 }} startIcon={<IconRefresh />} onClick={onConfirm}>
Refresh
</Button>
)}
{documentStore?.status === 'UPSERTING' && (
<Chip
variant='raised'
label='Upserting to Vector Store'
color='warning'
sx={{ borderRadius: 2, height: '100%' }}
/>
)}
{documentStore?.totalChunks > 0 && documentStore?.status !== 'UPSERTING' && (
<>
<Button
variant='contained'
sx={{
borderRadius: 2,
height: '100%'
}}
color='secondary'
startIcon={<IconListDetails />}
onClick={() => showStoredChunks('all')}
>
View Chunks
</Button>
<Button
variant='contained'
sx={{
borderRadius: 2,
height: '100%',
backgroundImage: `linear-gradient(to right, #13547a, #2f9e91)`,
'&:hover': {
backgroundImage: `linear-gradient(to right, #0b3d5b, #1a8377)`
}
}}
startIcon={<IconRowInsertTop />}
onClick={() => showVectorStore(documentStore.id)}
>
Upsert Config
</Button>
</>
)}
{documentStore?.totalChunks > 0 && documentStore?.status === 'UPSERTED' && (
<Button
variant='contained'
sx={{
borderRadius: 2,
height: '100%',
backgroundImage: `linear-gradient(to right, #3f5efb, #fc466b)`,
'&:hover': {
backgroundImage: `linear-gradient(to right, #2b4efb, #fe2752)`
}
}}
startIcon={<IconZoomScan />}
onClick={() => showVectorStoreQuery(documentStore.id)}
<Button
id='document-store-header-action-button'
aria-controls={open ? 'document-store-header-menu' : undefined}
aria-haspopup='true'
aria-expanded={open ? 'true' : undefined}
variant='outlined'
disableElevation
color='secondary'
onClick={handleClick}
sx={{ minWidth: 150 }}
endIcon={<KeyboardArrowDownIcon />}
>
More Actions
</Button>
<StyledMenu
id='document-store-header-menu'
MenuListProps={{
'aria-labelledby': 'document-store-header-menu-button'
}}
anchorEl={anchorEl}
open={open}
onClose={handleClose}
>
<MenuItem
disabled={documentStore?.totalChunks <= 0 || documentStore?.status === 'UPSERTING'}
onClick={() => showStoredChunks('all')}
disableRipple
>
<FileChunksIcon />
View & Edit Chunks
</MenuItem>
<MenuItem
disabled={documentStore?.totalChunks <= 0 || documentStore?.status === 'UPSERTING'}
onClick={() => showVectorStore(documentStore.id)}
disableRipple
>
<NoteAddIcon />
Upsert All Chunks
</MenuItem>
<MenuItem
disabled={documentStore?.totalChunks <= 0 || documentStore?.status !== 'UPSERTED'}
onClick={() => showVectorStoreQuery(documentStore.id)}
disableRipple
>
<SearchIcon />
Retrieval Query
</Button>
)}
</MenuItem>
<MenuItem
disabled={documentStore?.totalChunks <= 0 || documentStore?.status !== 'UPSERTED'}
onClick={() => onStoreRefresh(documentStore.id)}
disableRipple
title='Re-process all loaders and upsert all chunks'
>
<RefreshIcon />
Refresh
</MenuItem>
<Divider sx={{ my: 0.5 }} />
<MenuItem
onClick={() => onStoreDelete(documentStore.vectorStoreConfig, documentStore.recordManagerConfig)}
disableRipple
>
<FileDeleteIcon />
Delete
</MenuItem>
</StyledMenu>
</ViewHeader>
<DocumentStoreStatus status={documentStore?.status} />
{getSpecificDocumentStore.data?.whereUsed?.length > 0 && (
<Stack flexDirection='row' sx={{ gap: 2, alignItems: 'center', flexWrap: 'wrap' }}>
<div
@@ -584,6 +648,9 @@ const DocumentStoreDetails = () => {
documentStore?.recordManagerConfig
)
}
onChunkUpsert={() =>
navigate(`/document-stores/vector/${documentStore.id}/${loader.id}`)
}
/>
))}
</>
@@ -630,6 +697,7 @@ const DocumentStoreDetails = () => {
/>
)}
{isBackdropLoading && <BackdropLoader open={isBackdropLoading} />}
<ConfirmDialog />
</>
)
}
@@ -649,6 +717,9 @@ function LoaderRow(props) {
}
const formatSources = (source) => {
if (source && typeof source === 'string' && source.includes('base64')) {
return getFileName(source)
}
if (source && typeof source === 'string' && source.startsWith('[') && source.endsWith(']')) {
return JSON.parse(source).join(', ')
}
@@ -710,6 +781,10 @@ function LoaderRow(props) {
<FileChunksIcon />
View & Edit Chunks
</MenuItem>
<MenuItem onClick={props.onChunkUpsert} disableRipple>
<NoteAddIcon />
Upsert Chunks
</MenuItem>
<Divider sx={{ my: 0.5 }} />
<MenuItem onClick={props.onDeleteClick} disableRipple>
<FileDeleteIcon />
@@ -730,6 +805,7 @@ LoaderRow.propTypes = {
theme: PropTypes.any,
onViewChunksClick: PropTypes.func,
onEditClick: PropTypes.func,
onDeleteClick: PropTypes.func
onDeleteClick: PropTypes.func,
onChunkUpsert: PropTypes.func
}
export default DocumentStoreDetails
@@ -10,22 +10,36 @@ const DocumentStoreStatus = ({ status, isTableView }) => {
switch (status) {
case 'STALE':
return customization.isDarkMode
? [theme.palette.grey[400], theme.palette.grey[600], theme.palette.grey[700]]
? [theme.palette.grey[400], theme.palette.grey[600], theme.palette.grey[800]]
: [theme.palette.grey[300], theme.palette.grey[500], theme.palette.grey[700]]
case 'EMPTY':
return ['#673ab7', '#673ab7', '#673ab7']
return customization.isDarkMode
? ['#4a148c', '#6a1b9a', '#ffffff'] // Deep Purple
: ['#d1c4e9', '#9575cd', '#673ab7']
case 'SYNCING':
return customization.isDarkMode
? ['#ff6f00', '#ff8f00', '#ffffff'] // Amber
: ['#fff8e1', '#ffe57f', '#ffc107']
case 'UPSERTING':
return ['#fff8e1', '#ffe57f', '#ffc107']
return customization.isDarkMode
? ['#01579b', '#0277bd', '#ffffff'] // Light Blue
: ['#e1f5fe', '#4fc3f7', '#0288d1']
case 'SYNC':
return customization.isDarkMode
? ['#1b5e20', '#2e7d32', '#ffffff'] // Green
: ['#e8f5e9', '#81c784', '#43a047']
case 'UPSERTED':
return ['#cdf5d8', '#00e676', '#00c853']
return customization.isDarkMode
? ['#004d40', '#00695c', '#ffffff'] // Teal
: ['#e0f2f1', '#4db6ac', '#00897b']
case 'NEW':
return ['#e3f2fd', '#2196f3', '#1e88e5']
return customization.isDarkMode
? ['#0d47a1', '#1565c0', '#ffffff'] // Blue
: ['#e3f2fd', '#64b5f6', '#1e88e5']
default:
return customization.isDarkMode
? [theme.palette.grey[300], theme.palette.grey[500], theme.palette.grey[700]]
: [theme.palette.grey[300], theme.palette.grey[500], theme.palette.grey[700]]
: [theme.palette.grey[200], theme.palette.grey[400], theme.palette.grey[600]]
}
}
@@ -45,7 +59,8 @@ const DocumentStoreStatus = ({ status, isTableView }) => {
paddingTop: '3px',
paddingBottom: '3px',
paddingLeft: '10px',
paddingRight: '10px'
paddingRight: '10px',
width: 'fit-content'
}}
>
<div
@@ -186,9 +186,9 @@ const LoaderConfigPreviewChunks = () => {
setLoading(true)
const config = prepareConfig()
try {
const processResp = await documentStoreApi.processChunks(config)
const saveResp = await documentStoreApi.saveProcessingLoader(config)
setLoading(false)
if (processResp.data) {
if (saveResp.data) {
enqueueSnackbar({
message: 'File submitted for processing. Redirecting to Document Store..',
options: {
@@ -201,6 +201,8 @@ const LoaderConfigPreviewChunks = () => {
)
}
})
// don't wait for the process to complete, redirect to document store
documentStoreApi.processLoader(config, saveResp.data?.id)
navigate('/document-stores/' + storeId)
}
} catch (error) {
@@ -310,7 +310,7 @@ const ShowStoredChunks = () => {
</div>
<div style={{ marginRight: 20, display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
<IconLanguage style={{ marginRight: 10 }} size={20} />
{getChunksApi.data?.file?.totalChars?.toLocaleString()} characters
{getChunksApi.data?.characters?.toLocaleString()} characters
</div>
</div>
</div>
@@ -50,6 +50,10 @@ const VectorStoreConfigure = () => {
useNotifier()
const customization = useSelector((state) => state.customization)
const pathSegments = document.location.pathname.toString().split('/')
const storeId = pathSegments[3] || null
const docId = pathSegments[4] || null
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
@@ -213,7 +217,8 @@ const VectorStoreConfigure = () => {
const prepareConfigData = () => {
const data = {
storeId: storeId
storeId: storeId,
docId: docId
}
// Set embedding config
if (selectedEmbeddingsProvider.inputs) {
@@ -365,8 +370,6 @@ const VectorStoreConfigure = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [saveVectorStoreConfigApi.error])
const URLpath = document.location.pathname.toString().split('/')
const storeId = URLpath[URLpath.length - 1] === 'document-stores' ? '' : URLpath[URLpath.length - 1]
useEffect(() => {
getSpecificDocumentStoreApi.request(storeId)
@@ -432,420 +435,426 @@ const VectorStoreConfigure = () => {
{error ? (
<ErrorBoundary error={error} />
) : (
<Stack flexDirection='column' sx={{ gap: 3 }}>
<ViewHeader
isBackButton={true}
search={false}
title={getSpecificDocumentStoreApi.data?.name}
description='Configure Embeddings, Vector Store and Record Manager'
onBack={() => navigate(-1)}
>
{(Object.keys(selectedEmbeddingsProvider).length > 0 ||
Object.keys(selectedVectorStoreProvider).length > 0) && (
<Button
variant='outlined'
color='error'
sx={{
borderRadius: 2,
height: '100%'
}}
startIcon={<IconRefresh />}
onClick={() => resetVectorStoreConfig()}
<>
{!storeId && <div></div>}
{storeId && (
<Stack flexDirection='column' sx={{ gap: 3 }}>
<ViewHeader
isBackButton={true}
search={false}
title={getSpecificDocumentStoreApi.data?.name}
description='Configure Embeddings, Vector Store and Record Manager'
onBack={() => navigate(-1)}
>
Reset
</Button>
)}
{(Object.keys(selectedEmbeddingsProvider).length > 0 ||
Object.keys(selectedVectorStoreProvider).length > 0) && (
<Button
variant='outlined'
color='secondary'
sx={{
borderRadius: 2,
height: '100%'
}}
startIcon={<IconDeviceFloppy />}
onClick={() => saveVectorStoreConfig()}
>
Save Config
</Button>
)}
{Object.keys(selectedEmbeddingsProvider).length > 0 && Object.keys(selectedVectorStoreProvider).length > 0 && (
<Button
variant='contained'
sx={{
borderRadius: 2,
height: '100%',
backgroundImage: `linear-gradient(to right, #13547a, #2f9e91)`,
'&:hover': {
backgroundImage: `linear-gradient(to right, #0b3d5b, #1a8377)`
}
}}
startIcon={<IconRowInsertTop />}
onClick={() => tryAndInsertIntoStore()}
>
Upsert
</Button>
)}
<IconButton onClick={showUpsertHistoryDrawer} size='small' color='inherit' title='Upsert History'>
<IconClock />
</IconButton>
</ViewHeader>
<Steps />
<Grid container spacing={1}>
<Grid item xs={12} sm={4} md={4}>
{Object.keys(selectedEmbeddingsProvider).length === 0 ? (
<Button
onClick={showEmbeddingsList}
fullWidth={true}
startIcon={<Embeddings style={{ background: 'transparent', height: 32, width: 32 }} />}
sx={{
color: customization?.isDarkMode ? 'white' : 'inherit',
borderRadius: '10px',
minHeight: '200px',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 20%)',
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #e654bc, #4b86e7)`
: `linear-gradient(to right, #fadef2, #cfdcf1)`,
'&:hover': {
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #de32ac, #2d73e7)`
: `linear-gradient(to right, #f6c2e7, #b4cbf1)`
}
}}
>
Select Embeddings
</Button>
) : (
<Box>
<Grid container spacing='2'>
<Grid item xs={12} md={12} lg={12} sm={12}>
<div
style={{
display: 'flex',
flexDirection: 'column',
paddingRight: 15
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
p: 1
}}
>
{(Object.keys(selectedEmbeddingsProvider).length > 0 ||
Object.keys(selectedVectorStoreProvider).length > 0) && (
<Button
variant='outlined'
color='error'
sx={{
borderRadius: 2,
height: '100%'
}}
startIcon={<IconRefresh />}
onClick={() => resetVectorStoreConfig()}
>
Reset
</Button>
)}
{(Object.keys(selectedEmbeddingsProvider).length > 0 ||
Object.keys(selectedVectorStoreProvider).length > 0) && (
<Button
variant='outlined'
color='secondary'
sx={{
borderRadius: 2,
height: '100%'
}}
startIcon={<IconDeviceFloppy />}
onClick={() => saveVectorStoreConfig()}
>
Save Config
</Button>
)}
{Object.keys(selectedEmbeddingsProvider).length > 0 &&
Object.keys(selectedVectorStoreProvider).length > 0 && (
<Button
variant='contained'
sx={{
borderRadius: 2,
height: '100%',
backgroundImage: `linear-gradient(to right, #13547a, #2f9e91)`,
'&:hover': {
backgroundImage: `linear-gradient(to right, #0b3d5b, #1a8377)`
}
}}
startIcon={<IconRowInsertTop />}
onClick={() => tryAndInsertIntoStore()}
>
Upsert
</Button>
)}
<IconButton onClick={showUpsertHistoryDrawer} size='small' color='inherit' title='Upsert History'>
<IconClock />
</IconButton>
</ViewHeader>
<Steps />
<Grid container spacing={1}>
<Grid item xs={12} sm={4} md={4}>
{Object.keys(selectedEmbeddingsProvider).length === 0 ? (
<Button
onClick={showEmbeddingsList}
fullWidth={true}
startIcon={<Embeddings style={{ background: 'transparent', height: 32, width: 32 }} />}
sx={{
color: customization?.isDarkMode ? 'white' : 'inherit',
borderRadius: '10px',
minHeight: '200px',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 20%)',
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #e654bc, #4b86e7)`
: `linear-gradient(to right, #fadef2, #cfdcf1)`,
'&:hover': {
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #de32ac, #2d73e7)`
: `linear-gradient(to right, #f6c2e7, #b4cbf1)`
}
}}
>
Select Embeddings
</Button>
) : (
<Box>
<Grid container spacing='2'>
<Grid item xs={12} md={12} lg={12} sm={12}>
<div
style={{
width: 40,
height: 40,
borderRadius: '50%',
backgroundColor: 'white',
display: 'flex',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 25%)'
flexDirection: 'column',
paddingRight: 15
}}
>
{selectedEmbeddingsProvider.label ? (
<img
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
p: 1
}}
>
<div
style={{
width: '100%',
height: '100%',
padding: 7,
width: 40,
height: 40,
borderRadius: '50%',
objectFit: 'contain'
backgroundColor: 'white',
display: 'flex',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 25%)'
}}
alt={selectedEmbeddingsProvider.label ?? 'embeddings'}
src={`${baseURL}/api/v1/node-icon/${selectedEmbeddingsProvider?.name}`}
/>
) : (
<Embeddings color='black' />
)}
</div>
<Typography sx={{ ml: 2 }} variant='h3'>
{selectedEmbeddingsProvider.label}
</Typography>
<div style={{ flex: 1 }}></div>
<div
style={{
display: 'flex',
alignContent: 'center',
flexDirection: 'row'
}}
>
{Object.keys(selectedEmbeddingsProvider).length > 0 && (
<>
<IconButton
variant='outlined'
sx={{ ml: 1 }}
color='secondary'
onClick={showEmbeddingsList}
>
<IconEditCircle />
</IconButton>
</>
)}
</div>
</Box>
{selectedEmbeddingsProvider &&
Object.keys(selectedEmbeddingsProvider).length > 0 &&
(selectedEmbeddingsProvider.inputParams ?? [])
.filter((inputParam) => !inputParam.hidden)
.map((inputParam, index) => (
<DocStoreInputHandler
key={index}
data={selectedEmbeddingsProvider}
inputParam={inputParam}
isAdditionalParams={inputParam.additionalParams}
/>
))}
</div>
</Grid>
</Grid>
</Box>
)}
</Grid>
<Grid item xs={12} sm={4} md={4}>
{Object.keys(selectedVectorStoreProvider).length === 0 ? (
<Button
onClick={showVectorStoreList}
fullWidth={true}
startIcon={<Storage style={{ background: 'transparent', height: 32, width: 32 }} />}
sx={{
color: customization?.isDarkMode ? 'white' : 'inherit',
borderRadius: '10px',
minHeight: '200px',
opacity: isVectorStoreDisabled() ? 0.7 : 1,
boxShadow: isVectorStoreDisabled() ? 'none' : '0 2px 14px 0 rgb(32 40 45 / 20%)',
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #4d8ef1, #f1de5c)`
: `linear-gradient(to right, #b9d0f4, #fef9d7)`,
'&:hover': {
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #2576f2, #f0d72e)`
: `linear-gradient(to right, #9cbdf2, #fcf3b6)`
}
}}
disabled={isVectorStoreDisabled()}
>
Select Vector Store
</Button>
) : (
<Box>
<Grid container spacing='2'>
<Grid item xs={12} md={12} lg={12} sm={12}>
<div
style={{
display: 'flex',
flexDirection: 'column',
paddingRight: 15
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
p: 1
}}
>
<div
style={{
width: 40,
height: 40,
borderRadius: '50%',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 25%)'
}}
>
{selectedVectorStoreProvider.label ? (
<img
>
{selectedEmbeddingsProvider.label ? (
<img
style={{
width: '100%',
height: '100%',
padding: 7,
borderRadius: '50%',
objectFit: 'contain'
}}
alt={selectedEmbeddingsProvider.label ?? 'embeddings'}
src={`${baseURL}/api/v1/node-icon/${selectedEmbeddingsProvider?.name}`}
/>
) : (
<Embeddings color='black' />
)}
</div>
<Typography sx={{ ml: 2 }} variant='h3'>
{selectedEmbeddingsProvider.label}
</Typography>
<div style={{ flex: 1 }}></div>
<div
style={{
width: '100%',
height: '100%',
padding: 7,
borderRadius: '50%',
objectFit: 'contain'
display: 'flex',
alignContent: 'center',
flexDirection: 'row'
}}
alt={selectedVectorStoreProvider.label ?? 'embeddings'}
src={`${baseURL}/api/v1/node-icon/${selectedVectorStoreProvider?.name}`}
/>
) : (
<Embeddings color='black' />
)}
>
{Object.keys(selectedEmbeddingsProvider).length > 0 && (
<>
<IconButton
variant='outlined'
sx={{ ml: 1 }}
color='secondary'
onClick={showEmbeddingsList}
>
<IconEditCircle />
</IconButton>
</>
)}
</div>
</Box>
{selectedEmbeddingsProvider &&
Object.keys(selectedEmbeddingsProvider).length > 0 &&
(selectedEmbeddingsProvider.inputParams ?? [])
.filter((inputParam) => !inputParam.hidden)
.map((inputParam, index) => (
<DocStoreInputHandler
key={index}
data={selectedEmbeddingsProvider}
inputParam={inputParam}
isAdditionalParams={inputParam.additionalParams}
/>
))}
</div>
<Typography sx={{ ml: 2 }} variant='h3'>
{selectedVectorStoreProvider.label}
</Typography>
<div style={{ flex: 1 }}></div>
</Grid>
</Grid>
</Box>
)}
</Grid>
<Grid item xs={12} sm={4} md={4}>
{Object.keys(selectedVectorStoreProvider).length === 0 ? (
<Button
onClick={showVectorStoreList}
fullWidth={true}
startIcon={<Storage style={{ background: 'transparent', height: 32, width: 32 }} />}
sx={{
color: customization?.isDarkMode ? 'white' : 'inherit',
borderRadius: '10px',
minHeight: '200px',
opacity: isVectorStoreDisabled() ? 0.7 : 1,
boxShadow: isVectorStoreDisabled() ? 'none' : '0 2px 14px 0 rgb(32 40 45 / 20%)',
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #4d8ef1, #f1de5c)`
: `linear-gradient(to right, #b9d0f4, #fef9d7)`,
'&:hover': {
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #2576f2, #f0d72e)`
: `linear-gradient(to right, #9cbdf2, #fcf3b6)`
}
}}
disabled={isVectorStoreDisabled()}
>
Select Vector Store
</Button>
) : (
<Box>
<Grid container spacing='2'>
<Grid item xs={12} md={12} lg={12} sm={12}>
<div
style={{
display: 'flex',
alignContent: 'center',
flexDirection: 'row'
flexDirection: 'column',
paddingRight: 15
}}
>
{Object.keys(selectedVectorStoreProvider).length > 0 && (
<>
<IconButton
variant='outlined'
sx={{ ml: 1 }}
color='secondary'
onClick={showVectorStoreList}
>
<IconEditCircle />
</IconButton>
</>
)}
</div>
</Box>
{selectedVectorStoreProvider &&
Object.keys(selectedVectorStoreProvider).length > 0 &&
(selectedVectorStoreProvider.inputParams ?? [])
.filter((inputParam) => !inputParam.hidden)
.map((inputParam, index) => (
<DocStoreInputHandler
key={index}
data={selectedVectorStoreProvider}
inputParam={inputParam}
isAdditionalParams={inputParam.additionalParams}
/>
))}
</div>
</Grid>
</Grid>
</Box>
)}
</Grid>
<Grid item xs={12} sm={4} md={4}>
{Object.keys(selectedRecordManagerProvider).length === 0 ? (
<Button
onClick={showRecordManagerList}
fullWidth={true}
startIcon={
isRecordManagerUnavailable ? (
<></>
) : (
<DynamicFeed style={{ background: 'transparent', height: 32, width: 32 }} />
)
}
sx={{
color: customization?.isDarkMode ? 'white' : 'inherit',
borderRadius: '10px',
minHeight: '200px',
opacity: isRecordManagerDisabled() ? 0.7 : 1,
boxShadow: isRecordManagerDisabled() ? 'none' : '0 2px 14px 0 rgb(32 40 45 / 20%)',
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #f5db3f, #42daa7)`
: `linear-gradient(to right, #f9f1c0, #c7f1e3)`,
'&:hover': {
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #d9c238, #3dc295)`
: `linear-gradient(to right, #f6e99b, #a0f2d7)`
}
}}
disabled={isRecordManagerDisabled()}
>
{isRecordManagerUnavailable
? 'Record Manager is not applicable for selected Vector Store'
: 'Select Record Manager'}
</Button>
) : (
<Box>
<Grid container spacing='2'>
<Grid item xs={12} md={12} lg={12} sm={12}>
<div
style={{
display: 'flex',
flexDirection: 'column',
paddingRight: 15
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
p: 1
}}
>
<div
style={{
width: 40,
height: 40,
borderRadius: '50%',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 25%)'
}}
>
{selectedRecordManagerProvider.label ? (
<img
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
p: 1
}}
>
<div
style={{
width: '100%',
height: '100%',
padding: 7,
width: 40,
height: 40,
borderRadius: '50%',
objectFit: 'contain'
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 25%)'
}}
alt={selectedRecordManagerProvider.label ?? 'embeddings'}
src={`${baseURL}/api/v1/node-icon/${selectedRecordManagerProvider?.name}`}
/>
) : (
<Embeddings color='black' />
)}
>
{selectedVectorStoreProvider.label ? (
<img
style={{
width: '100%',
height: '100%',
padding: 7,
borderRadius: '50%',
objectFit: 'contain'
}}
alt={selectedVectorStoreProvider.label ?? 'embeddings'}
src={`${baseURL}/api/v1/node-icon/${selectedVectorStoreProvider?.name}`}
/>
) : (
<Embeddings color='black' />
)}
</div>
<Typography sx={{ ml: 2 }} variant='h3'>
{selectedVectorStoreProvider.label}
</Typography>
<div style={{ flex: 1 }}></div>
<div
style={{
display: 'flex',
alignContent: 'center',
flexDirection: 'row'
}}
>
{Object.keys(selectedVectorStoreProvider).length > 0 && (
<>
<IconButton
variant='outlined'
sx={{ ml: 1 }}
color='secondary'
onClick={showVectorStoreList}
>
<IconEditCircle />
</IconButton>
</>
)}
</div>
</Box>
{selectedVectorStoreProvider &&
Object.keys(selectedVectorStoreProvider).length > 0 &&
(selectedVectorStoreProvider.inputParams ?? [])
.filter((inputParam) => !inputParam.hidden)
.map((inputParam, index) => (
<DocStoreInputHandler
key={index}
data={selectedVectorStoreProvider}
inputParam={inputParam}
isAdditionalParams={inputParam.additionalParams}
/>
))}
</div>
<Typography sx={{ ml: 2 }} variant='h3'>
{selectedRecordManagerProvider.label}
</Typography>
<div style={{ flex: 1 }}></div>
</Grid>
</Grid>
</Box>
)}
</Grid>
<Grid item xs={12} sm={4} md={4}>
{Object.keys(selectedRecordManagerProvider).length === 0 ? (
<Button
onClick={showRecordManagerList}
fullWidth={true}
startIcon={
isRecordManagerUnavailable ? (
<></>
) : (
<DynamicFeed style={{ background: 'transparent', height: 32, width: 32 }} />
)
}
sx={{
color: customization?.isDarkMode ? 'white' : 'inherit',
borderRadius: '10px',
minHeight: '200px',
opacity: isRecordManagerDisabled() ? 0.7 : 1,
boxShadow: isRecordManagerDisabled() ? 'none' : '0 2px 14px 0 rgb(32 40 45 / 20%)',
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #f5db3f, #42daa7)`
: `linear-gradient(to right, #f9f1c0, #c7f1e3)`,
'&:hover': {
backgroundImage: customization?.isDarkMode
? `linear-gradient(to right, #d9c238, #3dc295)`
: `linear-gradient(to right, #f6e99b, #a0f2d7)`
}
}}
disabled={isRecordManagerDisabled()}
>
{isRecordManagerUnavailable
? 'Record Manager is not applicable for selected Vector Store'
: 'Select Record Manager'}
</Button>
) : (
<Box>
<Grid container spacing='2'>
<Grid item xs={12} md={12} lg={12} sm={12}>
<div
style={{
display: 'flex',
alignContent: 'center',
flexDirection: 'row'
flexDirection: 'column',
paddingRight: 15
}}
>
{Object.keys(selectedRecordManagerProvider).length > 0 && (
<>
<IconButton
variant='outlined'
sx={{ ml: 1 }}
color='secondary'
onClick={showRecordManagerList}
>
<IconEditCircle />
</IconButton>
</>
)}
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
p: 1
}}
>
<div
style={{
width: 40,
height: 40,
borderRadius: '50%',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 25%)'
}}
>
{selectedRecordManagerProvider.label ? (
<img
style={{
width: '100%',
height: '100%',
padding: 7,
borderRadius: '50%',
objectFit: 'contain'
}}
alt={selectedRecordManagerProvider.label ?? 'embeddings'}
src={`${baseURL}/api/v1/node-icon/${selectedRecordManagerProvider?.name}`}
/>
) : (
<Embeddings color='black' />
)}
</div>
<Typography sx={{ ml: 2 }} variant='h3'>
{selectedRecordManagerProvider.label}
</Typography>
<div style={{ flex: 1 }}></div>
<div
style={{
display: 'flex',
alignContent: 'center',
flexDirection: 'row'
}}
>
{Object.keys(selectedRecordManagerProvider).length > 0 && (
<>
<IconButton
variant='outlined'
sx={{ ml: 1 }}
color='secondary'
onClick={showRecordManagerList}
>
<IconEditCircle />
</IconButton>
</>
)}
</div>
</Box>
{selectedRecordManagerProvider &&
Object.keys(selectedRecordManagerProvider).length > 0 &&
(selectedRecordManagerProvider.inputParams ?? [])
.filter((inputParam) => !inputParam.hidden)
.map((inputParam, index) => (
<>
<DocStoreInputHandler
key={index}
data={selectedRecordManagerProvider}
inputParam={inputParam}
isAdditionalParams={inputParam.additionalParams}
/>
</>
))}
</div>
</Box>
{selectedRecordManagerProvider &&
Object.keys(selectedRecordManagerProvider).length > 0 &&
(selectedRecordManagerProvider.inputParams ?? [])
.filter((inputParam) => !inputParam.hidden)
.map((inputParam, index) => (
<>
<DocStoreInputHandler
key={index}
data={selectedRecordManagerProvider}
inputParam={inputParam}
isAdditionalParams={inputParam.additionalParams}
/>
</>
))}
</div>
</Grid>
</Grid>
</Box>
)}
</Grid>
</Grid>
</Stack>
</Grid>
</Grid>
</Box>
)}
</Grid>
</Grid>
</Stack>
)}
</>
)}
</MainCard>