1111import streamlit as st
1212
1313from llama_stack_ui .distribution .ui .modules .api import llama_stack_api
14+ from llama_stack_ui .distribution .ui .modules .local_extractors import (
15+ LOCAL_SUPPORTED_EXTENSIONS ,
16+ PROVIDER_SUPPORTED_EXTENSIONS ,
17+ create_text_file_from_extracted_content ,
18+ extract_text ,
19+ )
1420from llama_stack_ui .distribution .ui .modules .utils import get_vector_db_name
1521
1622
@@ -21,6 +27,7 @@ def _init_upload_page_session_state():
2127 "creation_message" : "" ,
2228 "selected_vector_db" : "" ,
2329 "newly_created_vdb" : None ,
30+ "extraction_method" : "provider" ,
2431 }
2532 for key , value in defaults .items ():
2633 if key not in st .session_state :
@@ -189,6 +196,9 @@ def _create_vector_database(vdb_name):
189196def _show_document_upload_ui (vector_db_name , vector_db_obj = None ):
190197 """Display UI for uploading documents to an existing vector database.
191198
199+ Shows an extraction method toggle that determines which file types are
200+ accepted and how they are processed before ingestion.
201+
192202 Args:
193203 vector_db_name (str): Name of the selected vector database
194204 vector_db_obj: The actual vector database object with identifier
@@ -200,44 +210,82 @@ def _show_document_upload_ui(vector_db_name, vector_db_obj=None):
200210
201211 _show_status ("upload_status" , "upload_message" )
202212
213+ local_label = (
214+ "Docling ("
215+ + ", " .join (LOCAL_SUPPORTED_EXTENSIONS ) + ")"
216+ )
217+ provider_label = (
218+ "LlamaStack Provider ("
219+ + ", " .join (PROVIDER_SUPPORTED_EXTENSIONS ) + ")"
220+ )
221+ method_options = [provider_label , local_label ]
222+
223+ selected_label = st .radio (
224+ "Extraction method" ,
225+ method_options ,
226+ key = "extraction_method_radio" ,
227+ horizontal = False ,
228+ help = "Local extraction converts .docx/.xlsx to text in the browser. "
229+ "LlamaStack Provider sends files directly to the server." ,
230+ )
231+
232+ is_local = selected_label == local_label
233+ st .session_state ["extraction_method" ] = "local" if is_local else "provider"
234+
235+ if is_local :
236+ accepted_types = [ext .lstrip ("." ) for ext in LOCAL_SUPPORTED_EXTENSIONS ]
237+ else :
238+ accepted_types = [ext .lstrip ("." ) for ext in PROVIDER_SUPPORTED_EXTENSIONS ]
239+
203240 upload_key = f"processed_files_{ vector_db_name } "
204241 if upload_key not in st .session_state :
205242 st .session_state [upload_key ] = set ()
206243
207244 uploaded_files = st .file_uploader (
208245 "Browse and select files to upload (files will upload automatically)" ,
209246 accept_multiple_files = True ,
210- type = [ "txt" , "pdf" , "doc" , "docx" , "md" ] ,
211- key = f"uploader_{ vector_db_name } " ,
247+ type = accepted_types ,
248+ key = f"uploader_{ vector_db_name } _ { st . session_state [ 'extraction_method' ] } " ,
212249 help = (
213- "Select one or more documents - they will be uploaded "
250+ "Select one or more documents — they will be uploaded "
214251 "automatically to this vector database"
215252 ),
216253 )
217254
218255 if uploaded_files :
219- file_set_id = frozenset ([f .name + str (f .size ) for f in uploaded_files ])
256+ new_files = [
257+ f for f in uploaded_files
258+ if f .name + str (f .size ) not in st .session_state [upload_key ]
259+ ]
220260
221- if file_set_id not in st .session_state [upload_key ]:
222- st .session_state [upload_key ].add (file_set_id )
261+ if new_files :
262+ for f in new_files :
263+ st .session_state [upload_key ].add (f .name + str (f .size ))
223264
224265 if vector_db_obj and hasattr (vector_db_obj , 'id' ):
225266 vector_db_id = vector_db_obj .id
226267 else :
227268 vector_db_id = vector_db_name
228269
229270 _upload_documents_to_database (
230- vector_db_name , uploaded_files , vector_db_id
271+ vector_db_name ,
272+ new_files ,
273+ vector_db_id ,
274+ extraction_method = st .session_state ["extraction_method" ],
231275 )
232276
233-
234- def _upload_documents_to_database (vector_db_name , uploaded_files , vector_db_id = None ):
277+ def _upload_documents_to_database (vector_db_name , uploaded_files , vector_db_id = None , extraction_method = "provider" ):
235278 """Upload documents to an existing vector database.
236279
280+ When extraction_method is "local", files are first converted to plain text
281+ using the local extractors and the resulting .txt content is uploaded.
282+ When "provider", files are sent directly to the LlamaStack server.
283+
237284 Args:
238285 vector_db_name (str): Name of the target vector database
239286 uploaded_files: List of uploaded files from Streamlit file uploader
240287 vector_db_id (str): The actual database identifier for API calls
288+ extraction_method (str): "local" for client-side extraction, "provider" for server-side
241289 """
242290 try :
243291 st .session_state ["upload_status" ] = None
@@ -251,16 +299,37 @@ def _upload_documents_to_database(vector_db_name, uploaded_files, vector_db_id=N
251299 actual_db_id = vector_db_id or vector_db_name
252300 uploaded_file_ids = []
253301
254- with st .spinner (f"Uploading { len (uploaded_files )} file(s)..." ):
302+ spinner_msg = (
303+ f"Extracting and uploading { len (uploaded_files )} file(s)..."
304+ if extraction_method == "local"
305+ else f"Uploading { len (uploaded_files )} file(s)..."
306+ )
307+
308+ with st .spinner (spinner_msg ):
255309 for uploaded_file in uploaded_files :
310+ original_filename = uploaded_file .name
311+
312+ if extraction_method == "local" :
313+ text_content = extract_text (uploaded_file , original_filename )
314+ file_to_upload = create_text_file_from_extracted_content (
315+ text_content , original_filename
316+ )
317+ else :
318+ file_to_upload = uploaded_file
319+
256320 file_response = llama_stack_api .client .files .create (
257- file = uploaded_file ,
321+ file = file_to_upload ,
258322 purpose = "assistants"
259323 )
260- llama_stack_api .client .vector_stores .files .create (
261- vector_store_id = actual_db_id ,
262- file_id = file_response .id ,
263- )
324+
325+ vs_file_kwargs = {
326+ "vector_store_id" : actual_db_id ,
327+ "file_id" : file_response .id ,
328+ }
329+ if extraction_method == "local" :
330+ vs_file_kwargs ["attributes" ] = {"source" : original_filename }
331+
332+ llama_stack_api .client .vector_stores .files .create (** vs_file_kwargs )
264333 uploaded_file_ids .append (file_response .id )
265334
266335 st .session_state ["upload_status" ] = "success"
0 commit comments