File size: 2,288 Bytes
94c6e47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62dea42
 
 
 
 
 
 
 
94c6e47
 
 
 
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
"""Hugging Face Space entry point.

Runs `python app.py`. Pulls the private dataset (index/ + originals/) if
STUDYHUB_DATASET is set, builds the StudyService, and launches the gated app.
Secrets/config come from Space Secrets (environment variables):
  STUDYHUB_DATASET   e.g. "your-user/studyhub-materials"  (private dataset)
  HF_TOKEN           read-only fine-grained token scoped to that dataset
  GROQ_API_KEY       (+ optional CEREBRAS_API_KEY)
  APP_USERS          "user:role:salt$hash, ..."  (from `python -m studyhub.app.make_user`)
  STUDYHUB_EMBEDDER  "bge-m3" (default) — must match the embedder used to build the index
  STUDYHUB_TITLE     optional display title
"""
from __future__ import annotations

import os
from pathlib import Path


def _maybe_pull_dataset() -> None:
    """Pull the private dataset and point the index/materials env vars at it. No-op locally."""
    repo = os.getenv("STUDYHUB_DATASET")
    if not repo:
        return
    from huggingface_hub import snapshot_download

    local = snapshot_download(
        repo_id=repo,
        repo_type="dataset",
        token=os.getenv("HF_TOKEN"),
        local_dir=os.getenv("STUDYHUB_DATA_DIR", "data"),
    )
    base = Path(local)
    os.environ.setdefault("STUDYHUB_INDEX_DIR", str(base / "index"))
    os.environ.setdefault("STUDYHUB_MATERIALS_DIR", str(base / "originals"))


def build_demo():
    _maybe_pull_dataset()
    from studyhub.app.auth import make_auth_fn, parse_users
    from studyhub.app.config import load_settings
    from studyhub.app.factory import build_service
    from studyhub.app.ui import build_app

    settings = load_settings()
    service = build_service(settings)
    users = parse_users(settings.app_users_raw)
    demo = build_app(service, title=settings.title)
    auth = make_auth_fn(users) if users else None
    return demo, auth


def main() -> None:
    demo, auth = build_demo()
    # Bind to all interfaces on the Space's port, and disable Node SSR (it errors on Spaces).
    # auth gates the whole app; never use share=True (it would bypass the gate).
    demo.queue(max_size=16).launch(
        server_name="0.0.0.0",
        server_port=int(os.getenv("PORT", "7860")),
        auth=auth,
        ssr_mode=False,
    )


if __name__ == "__main__":
    main()