Spaces:
Running
Running
File size: 6,913 Bytes
5ecb30e 9d07534 5ecb30e 9d07534 5ecb30e 9d07534 5ecb30e 9d07534 5ecb30e 9d07534 5ecb30e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | """Hugging Face loading screen, keeping SDK download work off the UI thread."""
from concurrent.futures import ThreadPoolExecutor
from queue import Empty, Queue
import streamlit as st
from hub_models import build_plan, discover_models, download_model, format_size, friendly_hub_error, check_hosted_download
from hub_models import CACHE_ROOT
from app_environment import hosted_mode, hosted_download_limit, new_session_directory, PRIVATE_CACHE_ROOT
MODEL_PRESETS = {
'SmolLM2 135M · small & quick': ('HuggingFaceTB/SmolLM2-135M', 'About 271 MB · English · safetensors'),
'GPT-2 · classic English model': ('openai-community/gpt2', 'About 549 MB · English · safetensors'),
'Gemma 3 1B · Q4 GGUF': (
'https://huggingface.co/lmstudio-community/gemma-3-1B-it-qat-GGUF/blob/main/gemma-3-1B-it-QAT-Q4_0.gguf',
'About 720 MB · quantized GGUF'),
'Qwen3 0.6B · multilingual': ('Qwen/Qwen3-0.6B', 'About 1.52 GB · multilingual · safetensors'),
}
def render_hub_loader(activate_model):
st.caption('Choose a suggested model or paste a Hugging Face link. Weights download directly to this Space.'
if hosted_mode() else 'Choose a suggested model or paste a Hugging Face link. Weights download to this computer.')
source = st.radio('Model source', ['Choose from list', 'Paste URL or repository ID'], horizontal=True, key='hf_source')
if source == 'Choose from list':
preset = st.selectbox('Suggested model', list(MODEL_PRESETS), key='hf_preset')
repo, description = MODEL_PRESETS[preset]
st.caption(description + ' · downloaded on first use; cached copies are reused')
else:
repo = st.text_input('Hugging Face repository or URL', placeholder='owner/model or https://huggingface.co/owner/model', key='hf_repo')
if hosted_mode():
st.caption(f'Up to {format_size(hosted_download_limit())} per model, subject to free storage. Larger vocabularies take longer to search.')
with st.expander('Revision & access token (optional)'):
revision = st.text_input('Revision', placeholder='main, branch, tag or commit', key='hf_revision')
token = st.text_input('Hugging Face read token', type='password', key='hf_token',
help='For private or gated models. Sent to this app server and Hugging Face for this session; it is not saved as a login.')
identity = (repo.strip(), revision.strip())
if st.button('Find model files', key='hf_find_files', type='primary', disabled=not repo.strip(), use_container_width=True):
st.session_state.pop('hf_catalog', None)
try:
with st.spinner('Reading Hugging Face repository…'):
st.session_state.hf_catalog = discover_models(repo, revision, token)
st.session_state.hf_catalog_identity = identity
except Exception as error:
st.error(friendly_hub_error(error, token))
catalog = st.session_state.get('hf_catalog')
if catalog is None or st.session_state.get('hf_catalog_identity') != identity:
return
st.link_button('View repository on Hugging Face', f'https://huggingface.co/{catalog.repo_id}')
if not catalog.choices:
st.info('No supported weights found. Choose a single-file GGUF, standalone safetensors, or a safetensors index. Split GGUF and PyTorch .bin files are not supported.')
return
preferred = catalog.choices.index(catalog.preferred) if catalog.preferred else 0
selection = st.selectbox('Model weights', catalog.choices, index=preferred,
key=f'hf_weights:{catalog.repo_id}:{catalog.commit}:{catalog.preferred}')
private = hosted_mode() and bool(token)
if private and 'private_hub_cache' not in st.session_state:
st.session_state.private_hub_cache = new_session_directory(PRIVATE_CACHE_ROOT)
cache_root = st.session_state.private_hub_cache if private else CACHE_ROOT
plan_key = (catalog.repo_id, catalog.commit, selection, str(cache_root))
plans = st.session_state.setdefault('hf_plans', {})
try:
if plan_key not in plans:
with st.spinner('Checking required model files…'):
plans[plan_key] = build_plan(catalog, selection, token, cache_root=cache_root)
plan = plans[plan_key]
except Exception as error:
st.error(friendly_hub_error(error, token))
return
st.caption(f'{len(plan.weight_files)} weights file(s) · {format_size(plan.size)} total · revision {catalog.commit[:12]}')
if plan.embeddings_only:
st.caption('Only shards containing recognised token embeddings will be downloaded.')
elif selection.endswith('.index.json'):
st.caption('Embedding names were not recognised in this index; all listed weight shards will be downloaded.')
with st.expander('Files to download'):
for filename in plan.files:
st.text(f'{filename} · {format_size(catalog.files.get(filename))}')
try:
check_hosted_download(plan)
except (ValueError, OSError) as error:
st.info(str(error))
return
load_label = 'Load into Space' if hosted_mode() else 'Download & load'
if st.button(load_label, key='hf_download', type='primary', use_container_width=True):
events = Queue()
progress = st.progress(0, text='Preparing download…')
try:
with ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(download_model, plan, token, lambda done, text: events.put((done, text)))
while not future.done():
try:
done, text = events.get(timeout=.15)
# Drop outdated progress events without touching Streamlit on a worker.
while not events.empty():
done, text = events.get_nowait()
progress.progress(done, text=text)
except Empty:
pass
model_path, tokenizer_path = future.result()
progress.progress(1., text='Download complete. Reading embeddings…')
activate_model(model_path, tokenizer_path, f'{catalog.repo_id} · {selection}')
st.session_state.clear_hub_token = True
st.rerun()
except Exception as error:
st.error(friendly_hub_error(error, token))
finally:
progress.empty()
if private:
st.caption('Token-authenticated downloads use a private session folder, removed when you clear the model. The Space owner operates this server.')
else:
st.caption('Downloads are cached and reused. Clearing a model keeps public downloaded files. Space restarts may clear the cache.' if hosted_mode() else 'Downloads are cached in this project’s .model-cache folder and reused. Clearing a model keeps its downloaded files.')
|