"""Local file browser rendered inside Streamlit, without desktop GUI calls.""" from pathlib import Path import streamlit as st from app_environment import hosted_mode def close_picker(): st.session_state.picker_open = False def set_directory(path): target = Path(path).expanduser() try: if not target.is_dir(): raise ValueError('Folder not found or not accessible.') st.session_state.picker_directory = str(target.resolve()) st.session_state.picker_address = str(target.resolve()) st.session_state.pop('picker_error', None) except (OSError, ValueError) as e: st.session_state.picker_error = str(e) def navigate_address(): set_directory(st.session_state.picker_address.strip().strip('"')) def choose_file(path): st.session_state.pending_model = str(path.resolve()) close_picker() def file_size(size): return f'{size / 1024**3:.2f} GB' if size >= 1024**3 else f'{size / 1024**2:.1f} MB' @st.dialog('Open model', width='large', on_dismiss=close_picker) def show_model_picker(): if hosted_mode(): st.error('Server filesystem browsing is disabled in the hosted app. Use uploads or Hugging Face instead.') return current = Path(st.session_state.get('picker_directory', str(Path.cwd()))) if 'picker_address' not in st.session_state: st.session_state.picker_address = str(current) up, address = st.columns([1, 8], vertical_alignment='bottom') up.button('โ†‘ Up', disabled=current == current.parent, on_click=set_directory, args=(current.parent,), use_container_width=True) address.text_input('Folder path', key='picker_address', on_change=navigate_address, placeholder='Paste a folder path and press Enter') current = Path(st.session_state.get('picker_directory', str(Path.cwd()))) if 'picker_error' in st.session_state: st.error(st.session_state.picker_error) st.caption(f'Showing: {current}') try: entries = sorted(current.iterdir(), key=lambda p: p.name.lower()) folders = [p for p in entries if p.is_dir() and not p.name.startswith('.')] files = [p for p in entries if p.is_file() and p.suffix.lower() in {'.gguf', '.safetensors'}] except OSError as e: st.error(f'Could not read this folder: {e}') return with st.container(height=300, border=True): for folder in folders: st.button(f'๐Ÿ“ {folder.name}', key=f'folder:{folder}', on_click=set_directory, args=(folder,), use_container_width=True) for file in files: label, size = st.columns([5, 1], vertical_alignment='center') if label.button(f'๐Ÿ“„ {file.name}', key=f'file:{file}', use_container_width=True): choose_file(file) st.rerun() try: size.caption(file_size(file.stat().st_size)) except OSError: size.caption('Unavailable') if not files: st.info('No GGUF or safetensors files here. Open a subfolder or enter another path above.') count, cancel = st.columns([5, 1], vertical_alignment='center') count.caption(f'{len(folders)} folders ยท {len(files)} model files ยท Click a model to select it') if cancel.button('Cancel', use_container_width=True): close_picker() st.rerun()