Spaces:
Running
Running
Create model_picker.py
Browse files- model_picker.py +80 -0
model_picker.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Local file browser rendered inside Streamlit, without desktop GUI calls."""
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
import streamlit as st
|
| 5 |
+
from app_environment import hosted_mode
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def close_picker():
|
| 9 |
+
st.session_state.picker_open = False
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def set_directory(path):
|
| 13 |
+
target = Path(path).expanduser()
|
| 14 |
+
try:
|
| 15 |
+
if not target.is_dir():
|
| 16 |
+
raise ValueError('Folder not found or not accessible.')
|
| 17 |
+
st.session_state.picker_directory = str(target.resolve())
|
| 18 |
+
st.session_state.picker_address = str(target.resolve())
|
| 19 |
+
st.session_state.pop('picker_error', None)
|
| 20 |
+
except (OSError, ValueError) as e:
|
| 21 |
+
st.session_state.picker_error = str(e)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def navigate_address():
|
| 25 |
+
set_directory(st.session_state.picker_address.strip().strip('"'))
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def choose_file(path):
|
| 29 |
+
st.session_state.pending_model = str(path.resolve())
|
| 30 |
+
close_picker()
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def file_size(size):
|
| 34 |
+
return f'{size / 1024**3:.2f} GB' if size >= 1024**3 else f'{size / 1024**2:.1f} MB'
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@st.dialog('Open model', width='large', on_dismiss=close_picker)
|
| 38 |
+
def show_model_picker():
|
| 39 |
+
if hosted_mode():
|
| 40 |
+
st.error('Server filesystem browsing is disabled in the hosted app. Use uploads or Hugging Face instead.')
|
| 41 |
+
return
|
| 42 |
+
current = Path(st.session_state.get('picker_directory', str(Path.cwd())))
|
| 43 |
+
if 'picker_address' not in st.session_state:
|
| 44 |
+
st.session_state.picker_address = str(current)
|
| 45 |
+
up, address = st.columns([1, 8], vertical_alignment='bottom')
|
| 46 |
+
up.button('↑ Up', disabled=current == current.parent, on_click=set_directory,
|
| 47 |
+
args=(current.parent,), use_container_width=True)
|
| 48 |
+
address.text_input('Folder path', key='picker_address', on_change=navigate_address,
|
| 49 |
+
placeholder='Paste a folder path and press Enter')
|
| 50 |
+
current = Path(st.session_state.get('picker_directory', str(Path.cwd())))
|
| 51 |
+
if 'picker_error' in st.session_state:
|
| 52 |
+
st.error(st.session_state.picker_error)
|
| 53 |
+
st.caption(f'Showing: {current}')
|
| 54 |
+
try:
|
| 55 |
+
entries = sorted(current.iterdir(), key=lambda p: p.name.lower())
|
| 56 |
+
folders = [p for p in entries if p.is_dir() and not p.name.startswith('.')]
|
| 57 |
+
files = [p for p in entries if p.is_file() and p.suffix.lower() in {'.gguf', '.safetensors'}]
|
| 58 |
+
except OSError as e:
|
| 59 |
+
st.error(f'Could not read this folder: {e}')
|
| 60 |
+
return
|
| 61 |
+
with st.container(height=300, border=True):
|
| 62 |
+
for folder in folders:
|
| 63 |
+
st.button(f'📁 {folder.name}', key=f'folder:{folder}', on_click=set_directory,
|
| 64 |
+
args=(folder,), use_container_width=True)
|
| 65 |
+
for file in files:
|
| 66 |
+
label, size = st.columns([5, 1], vertical_alignment='center')
|
| 67 |
+
if label.button(f'📄 {file.name}', key=f'file:{file}', use_container_width=True):
|
| 68 |
+
choose_file(file)
|
| 69 |
+
st.rerun()
|
| 70 |
+
try:
|
| 71 |
+
size.caption(file_size(file.stat().st_size))
|
| 72 |
+
except OSError:
|
| 73 |
+
size.caption('Unavailable')
|
| 74 |
+
if not files:
|
| 75 |
+
st.info('No GGUF or safetensors files here. Open a subfolder or enter another path above.')
|
| 76 |
+
count, cancel = st.columns([5, 1], vertical_alignment='center')
|
| 77 |
+
count.caption(f'{len(folders)} folders · {len(files)} model files · Click a model to select it')
|
| 78 |
+
if cancel.button('Cancel', use_container_width=True):
|
| 79 |
+
close_picker()
|
| 80 |
+
st.rerun()
|