Skip to content

Commit ad06798

Browse files
authored
Bugfix/Upsert API for file loader (#5096)
* fix upser api for file loader * - Introduced loaderName property in IDocumentStoreUpsertData interface. - Updated upsertDocStore function to utilize loaderName if provided. - Enhanced DocStoreAPIDialog to allow loaderName customization in API requests. - Modified DocumentStoreDetail to display file names when available, improving source formatting logic.
1 parent 9cac8d7 commit ad06798

File tree

5 files changed

+79
-8
lines changed

5 files changed

+79
-8
lines changed

packages/components/nodes/documentloaders/File/File.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,10 @@ class File_DocumentLoaders implements INode {
136136

137137
let files: string[] = []
138138
const fileBlobs: { blob: Blob; ext: string }[] = []
139+
const processRaw = options.processRaw
139140

140141
//FILE-STORAGE::["CONTRIBUTING.md","LICENSE.md","README.md"]
141-
const totalFiles = getOverrideFileInputs(nodeData) || fileBase64
142+
const totalFiles = getOverrideFileInputs(nodeData, processRaw) || fileBase64
142143
if (totalFiles.startsWith('FILE-STORAGE::')) {
143144
const fileName = totalFiles.replace('FILE-STORAGE::', '')
144145
if (fileName.startsWith('[') && fileName.endsWith(']')) {
@@ -298,7 +299,7 @@ class File_DocumentLoaders implements INode {
298299
}
299300
}
300301

301-
const getOverrideFileInputs = (nodeData: INodeData) => {
302+
const getOverrideFileInputs = (nodeData: INodeData, processRaw: boolean) => {
302303
const txtFileBase64 = nodeData.inputs?.txtFile as string
303304
const pdfFileBase64 = nodeData.inputs?.pdfFile as string
304305
const jsonFileBase64 = nodeData.inputs?.jsonFile as string
@@ -347,6 +348,10 @@ const getOverrideFileInputs = (nodeData: INodeData) => {
347348
files.push(...removePrefix(powerpointFileBase64))
348349
}
349350

351+
if (processRaw) {
352+
return files.length ? JSON.stringify(files) : ''
353+
}
354+
350355
return files.length ? `FILE-STORAGE::${JSON.stringify(files)}` : ''
351356
}
352357

packages/server/src/Interface.DocumentStore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export interface IDocumentStoreUpsertData {
8181
replaceExisting?: boolean
8282
createNewDocStore?: boolean
8383
docStore?: IDocumentStore
84+
loaderName?: string
8485
loader?: {
8586
name: string
8687
config: ICommonObject

packages/server/src/services/documentstore/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,8 @@ const _splitIntoChunks = async (appDataSource: DataSource, componentNodes: IComp
573573
chatflowid: uuidv4(),
574574
appDataSource,
575575
databaseEntities,
576-
logger
576+
logger,
577+
processRaw: true
577578
}
578579
const docNodeInstance = new nodeModule.nodeClass()
579580
let docs: IDocument[] = await docNodeInstance.init(nodeData, '', options)
@@ -1727,6 +1728,11 @@ const upsertDocStore = async (
17271728
...newLoader?.config
17281729
}
17291730

1731+
// Override loaderName if it's provided directly in data
1732+
if (data.loaderName) {
1733+
loaderName = data.loaderName
1734+
}
1735+
17301736
splitterName = newSplitter?.name ? getComponentLabelFromName(newSplitter?.name) : splitterName
17311737
splitterId = newSplitter?.name || splitterId
17321738
splitterConfig = {

packages/ui/src/views/docstore/DocStoreAPIDialog.jsx

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,32 @@ import { createPortal } from 'react-dom'
22
import { useState, useEffect } from 'react'
33
import PropTypes from 'prop-types'
44
import { MemoizedReactMarkdown } from '@/ui-component/markdown/MemoizedReactMarkdown'
5-
import { Typography, Stack, Card, Accordion, AccordionSummary, AccordionDetails, Dialog, DialogContent, DialogTitle } from '@mui/material'
5+
import {
6+
Typography,
7+
Stack,
8+
Card,
9+
Accordion,
10+
AccordionSummary,
11+
AccordionDetails,
12+
Dialog,
13+
DialogContent,
14+
DialogTitle,
15+
Box
16+
} from '@mui/material'
617
import { TableViewOnly } from '@/ui-component/table/Table'
718
import documentstoreApi from '@/api/documentstore'
819
import useApi from '@/hooks/useApi'
920
import { useTheme } from '@mui/material/styles'
21+
import { useSelector } from 'react-redux'
1022
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
23+
import { IconInfoCircle } from '@tabler/icons-react'
1124
import { baseURL } from '@/store/constant'
1225

1326
const DocStoreAPIDialog = ({ show, dialogProps, onCancel }) => {
1427
const [nodeConfig, setNodeConfig] = useState({})
1528
const [values, setValues] = useState('')
1629
const theme = useTheme()
30+
const customization = useSelector((state) => state.customization)
1731
const [nodeConfigExpanded, setNodeConfigExpanded] = useState({})
1832

1933
const getConfigApi = useApi(documentstoreApi.getDocumentStoreConfig)
@@ -38,6 +52,7 @@ body_data = {
3852
"metadata": {}, # Add additional metadata to the document chunks
3953
"replaceExisting": True, # Replace existing document with the new upserted chunks
4054
"createNewDocStore": False, # Create a new document store
55+
"loaderName": "Custom Loader Name", # Override the loader name
4156
"splitter": json.dumps({"config":{"chunkSize":20000}}) # Override existing configuration
4257
# "loader": "",
4358
# "vectorStore": "",
@@ -64,6 +79,7 @@ print(output)
6479
let formData = new FormData();
6580
formData.append("files", input.files[0]);
6681
formData.append("docId", "${dialogProps.loaderId}");
82+
formData.append("loaderName", "Custom Loader Name");
6783
formData.append("splitter", JSON.stringify({"config":{"chunkSize":20000}}));
6884
// Add additional metadata to the document chunks
6985
formData.append("metadata", "{}");
@@ -103,6 +119,7 @@ curl -X POST ${baseURL}/api/v1/document-store/upsert/${dialogProps.storeId} \\
103119
-H "Authorization: Bearer <your_api_key_here>" \\
104120
-F "files=@<file-path>" \\
105121
-F "docId=${dialogProps.loaderId}" \\
122+
-F "loaderName=Custom Loader Name" \\
106123
-F "splitter={"config":{"chunkSize":20000}}" \\
107124
-F "metadata={}" \\
108125
-F "replaceExisting=true" \\
@@ -139,6 +156,7 @@ output = query({
139156
"metadata": "{}", # Add additional metadata to the document chunks
140157
"replaceExisting": True, # Replace existing document with the new upserted chunks
141158
"createNewDocStore": False, # Create a new document store
159+
"loaderName": "Custom Loader Name", # Override the loader name
142160
# Override existing configuration
143161
"loader": {
144162
"config": {
@@ -176,10 +194,11 @@ async function query(data) {
176194
}
177195
178196
query({
179-
"docId": "${dialogProps.loaderId},
197+
"docId": "${dialogProps.loaderId}",
180198
"metadata": "{}", // Add additional metadata to the document chunks
181199
"replaceExisting": true, // Replace existing document with the new upserted chunks
182200
"createNewDocStore": false, // Create a new document store
201+
"loaderName": "Custom Loader Name", // Override the loader name
183202
// Override existing configuration
184203
"loader": {
185204
"config": {
@@ -209,6 +228,7 @@ curl -X POST ${baseURL}/api/v1/document-store/upsert/${dialogProps.storeId} \\
209228
"metadata": "{}",
210229
"replaceExisting": true,
211230
"createNewDocStore": false,
231+
"loaderName": "Custom Loader Name",
212232
"loader": {
213233
"config": {
214234
"text": "This is a new text"
@@ -304,6 +324,37 @@ curl -X POST ${baseURL}/api/v1/document-store/upsert/${dialogProps.storeId} \\
304324
{dialogProps.title}
305325
</DialogTitle>
306326
<DialogContent>
327+
{/* Info Box */}
328+
<Box
329+
sx={{
330+
display: 'flex',
331+
alignItems: 'center',
332+
padding: 2,
333+
mb: 3,
334+
background: customization.isDarkMode
335+
? 'linear-gradient(135deg, rgba(33, 150, 243, 0.2) 0%, rgba(33, 150, 243, 0.1) 100%)'
336+
: 'linear-gradient(135deg, rgba(33, 150, 243, 0.1) 0%, rgba(33, 150, 243, 0.05) 100%)',
337+
color: customization.isDarkMode ? 'white' : '#333333',
338+
fontWeight: 400,
339+
borderRadius: 2,
340+
border: `1px solid ${customization.isDarkMode ? 'rgba(33, 150, 243, 0.3)' : 'rgba(33, 150, 243, 0.2)'}`,
341+
gap: 1.5
342+
}}
343+
>
344+
<IconInfoCircle
345+
size={20}
346+
style={{
347+
color: customization.isDarkMode ? '#64b5f6' : '#1976d2',
348+
flexShrink: 0
349+
}}
350+
/>
351+
<Box sx={{ flex: 1 }}>
352+
<strong>Note:</strong> Upsert API can only be used when the existing document loader has been upserted before.
353+
</Box>
354+
</Box>
355+
356+
{/** info */}
357+
307358
<MemoizedReactMarkdown>{values}</MemoizedReactMarkdown>
308359

309360
<Typography sx={{ mt: 3, mb: 1 }}>You can override existing configurations:</Typography>

packages/ui/src/views/docstore/DocumentStoreDetail.jsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -756,14 +756,20 @@ function LoaderRow(props) {
756756
setAnchorEl(null)
757757
}
758758

759-
const formatSources = (source) => {
759+
const formatSources = (files, source) => {
760+
// Prefer files.name when files array exists and has items
761+
if (files && Array.isArray(files) && files.length > 0) {
762+
return files.map((file) => file.name).join(', ')
763+
}
764+
765+
// Fallback to original source logic
760766
if (source && typeof source === 'string' && source.includes('base64')) {
761767
return getFileName(source)
762768
}
763769
if (source && typeof source === 'string' && source.startsWith('[') && source.endsWith(']')) {
764770
return JSON.parse(source).join(', ')
765771
}
766-
return source
772+
return source || 'No source'
767773
}
768774

769775
return (
@@ -784,7 +790,9 @@ function LoaderRow(props) {
784790
{props.loader.loaderName}
785791
</StyledTableCell>
786792
<StyledTableCell onClick={props.onViewChunksClick}>{props.loader.splitterName ?? 'None'}</StyledTableCell>
787-
<StyledTableCell onClick={props.onViewChunksClick}>{formatSources(props.loader.source)}</StyledTableCell>
793+
<StyledTableCell onClick={props.onViewChunksClick}>
794+
{formatSources(props.loader.files, props.loader.source)}
795+
</StyledTableCell>
788796
<StyledTableCell onClick={props.onViewChunksClick}>
789797
{props.loader.totalChunks && <Chip variant='outlined' size='small' label={props.loader.totalChunks.toLocaleString()} />}
790798
</StyledTableCell>

0 commit comments

Comments
 (0)