1
1
import React , { useState } from 'react'
2
2
import { TextField , Button , Box , Typography , Table , TableHead , TableBody , TableRow , TableCell , Paper , IconButton , Dialog , DialogTitle , styled } from '@mui/material'
3
- import apiClient from '../util/apiClient'
3
+ import apiClient , { postAbortableStream } from '../ ../util/apiClient'
4
4
import { useMutation , useQuery } from '@tanstack/react-query'
5
5
import { CloudUpload , Settings } from '@mui/icons-material'
6
- import Markdown from './Banner/Markdown'
6
+ import Markdown from '.. /Banner/Markdown'
7
7
import { useSnackbar } from 'notistack'
8
+ import { ProgressReporter } from './ProgressReporter'
8
9
9
10
type RagResponse = {
10
11
id : string
@@ -69,13 +70,12 @@ const useUploadMutation = (index: RagIndexAttributes | null) => {
69
70
formData . append ( 'files' , file )
70
71
} )
71
72
72
- const response = await apiClient . put ( `/rag/indices/${ index . id } /upload` , formData , {
73
- headers : {
74
- 'Content-Type' : 'multipart/form-data' ,
75
- } ,
76
- } )
73
+ const { stream } = await postAbortableStream ( `/rag/indices/${ index . id } /upload` , formData )
74
+ if ( ! stream ) {
75
+ throw new Error ( 'No stream returned from server' )
76
+ }
77
77
78
- return response . data
78
+ return stream
79
79
} ,
80
80
} )
81
81
return mutation
@@ -105,6 +105,7 @@ const Rag: React.FC = () => {
105
105
const [ response , setResponse ] = useState < RagResponse [ ] | null > ( null )
106
106
const uploadMutation = useUploadMutation ( selectedIndex )
107
107
const [ modalOpen , setModalOpen ] = useState ( false )
108
+ const [ stream , setStream ] = useState < ReadableStream | null > ( null )
108
109
109
110
const handleSubmit = async ( event : React . FormEvent ) => {
110
111
event . preventDefault ( )
@@ -131,39 +132,40 @@ const Rag: React.FC = () => {
131
132
< Box sx = { { display : 'flex' , gap : 2 } } >
132
133
< Dialog open = { ! ! selectedIndex && modalOpen } onClose = { ( ) => setModalOpen ( false ) } >
133
134
< DialogTitle > Edit { selectedIndex ?. metadata ?. name } </ DialogTitle >
134
- < Box sx = { { padding : 2 , display : 'flex' , gap : 2 } } >
135
- < Button component = "label" role = { undefined } variant = "contained" tabIndex = { - 1 } startIcon = { < CloudUpload /> } disabled = { uploadMutation . isPending } >
136
- { uploadMutation . isPending ? 'Uploading...' : 'Upload Files' }
137
- < VisuallyHiddenInput
138
- type = "file"
139
- onChange = { async ( event ) => {
140
- const files = event . target . files
141
- console . log ( 'Files selected:' , files )
142
- if ( files && files . length > 0 ) {
143
- await uploadMutation . mutateAsync ( files )
135
+ < Box sx = { { padding : 2 } } >
136
+ < Box sx = { { display : 'flex' , gap : 2 } } >
137
+ < Button component = "label" role = { undefined } variant = "contained" tabIndex = { - 1 } startIcon = { < CloudUpload /> } disabled = { uploadMutation . isPending } >
138
+ { uploadMutation . isPending ? 'Uploading...' : 'Upload Files' }
139
+ < VisuallyHiddenInput
140
+ type = "file"
141
+ onChange = { async ( event ) => {
142
+ const files = event . target . files
143
+ console . log ( 'Files selected:' , files )
144
+ if ( files && files . length > 0 ) {
145
+ const stream = await uploadMutation . mutateAsync ( files )
146
+ setStream ( stream )
147
+ }
148
+ } }
149
+ multiple
150
+ />
151
+ </ Button >
152
+ < Button
153
+ variant = "text"
154
+ color = "error"
155
+ onClick = { async ( ) => {
156
+ if ( selectedIndex && window . confirm ( `Are you sure you want to delete index ${ selectedIndex . metadata . name } ?` ) ) {
157
+ await deleteIndexMutation . mutateAsync ( selectedIndex . id )
158
+ setSelectedIndex ( null )
144
159
refetch ( )
145
- setModalOpen ( false )
146
- enqueueSnackbar ( 'Files uploaded successfully' , {
147
- variant : 'success' ,
148
- } )
149
160
}
150
161
} }
151
- multiple
152
- />
153
- </ Button >
154
- < Button
155
- variant = "text"
156
- color = "error"
157
- onClick = { async ( ) => {
158
- if ( selectedIndex && window . confirm ( `Are you sure you want to delete index ${ selectedIndex . metadata . name } ?` ) ) {
159
- await deleteIndexMutation . mutateAsync ( selectedIndex . id )
160
- setSelectedIndex ( null )
161
- refetch ( )
162
- }
163
- } }
164
- >
165
- Delete Index
166
- </ Button >
162
+ >
163
+ Delete Index
164
+ </ Button >
165
+ </ Box >
166
+ < Box mt = { 2 } >
167
+ < ProgressReporter stream = { stream } />
168
+ </ Box >
167
169
</ Box >
168
170
</ Dialog >
169
171
< Box >
@@ -247,7 +249,9 @@ const Rag: React.FC = () => {
247
249
{ response . map ( ( doc ) => (
248
250
< Paper key = { doc . id } sx = { { marginBottom : 2 , p : 1 } } elevation = { 2 } >
249
251
< Typography variant = "caption" > Score: { doc . value . score } </ Typography >
250
- < Typography variant = "subtitle1" fontFamily = "monospace" mb = { 2 } > { JSON . stringify ( doc . value . metadata , null , 2 ) } </ Typography >
252
+ < Typography variant = "subtitle1" fontFamily = "monospace" mb = { 2 } >
253
+ { JSON . stringify ( doc . value . metadata , null , 2 ) }
254
+ </ Typography >
251
255
{ doc . value . metadata . type === 'md' ? (
252
256
< Markdown > { doc . value . content } </ Markdown >
253
257
) : (
0 commit comments