Spaces:
Sleeping
Sleeping
| """Docker-Space entry point: pull the dataset, build the app, run uvicorn. | |
| Secrets/config (Space Secrets / env): | |
| STUDYHUB_DATASET private dataset (index + originals + app/ + uploads/) | |
| HF_TOKEN WRITE-scoped token (pulls the dataset AND persists users/history) | |
| GROQ_API_KEY (+ CEREBRAS_API_KEY) generation | |
| APP_USERS seed admin(s): "owner:admin:salt$hash" | |
| STUDYHUB_INVITE_CODE the class code classmates use to register | |
| STUDYHUB_EMBEDDER bge-m3 | |
| STUDYHUB_SESSION_SECRET random string for signing session cookies | |
| """ | |
| import os | |
| from pathlib import Path | |
| def _maybe_pull_dataset() -> None: | |
| repo = os.getenv("STUDYHUB_DATASET") | |
| if not repo: | |
| return | |
| from huggingface_hub import snapshot_download | |
| from ..accounts.uploads import merge_uploads_into_materials | |
| local = snapshot_download(repo_id=repo, repo_type="dataset", token=os.getenv("HF_TOKEN"), | |
| local_dir=os.getenv("STUDYHUB_DATA_DIR", "data"), | |
| allow_patterns=["index/**", "originals/**", "uploads/**"]) | |
| base = Path(local) | |
| merge_uploads_into_materials(base) # so /api/download can serve uploaded files too | |
| os.environ.setdefault("STUDYHUB_INDEX_DIR", str(base / "index")) | |
| os.environ.setdefault("STUDYHUB_MATERIALS_DIR", str(base / "originals")) | |
| def build_app(): | |
| _maybe_pull_dataset() | |
| from studyhub.accounts.decks import DeckStore | |
| from studyhub.accounts.history import HistoryStore | |
| from studyhub.accounts.invites import InviteStore | |
| from studyhub.accounts.notes import NotesStore | |
| from studyhub.accounts.store import HfDatasetStore, LocalStore | |
| from studyhub.accounts.users import UserStore | |
| from studyhub.app.auth import parse_users | |
| from studyhub.app.config import load_settings | |
| from studyhub.app.factory import build_service | |
| from studyhub.web.api import create_app | |
| settings = load_settings() | |
| service = build_service(settings) | |
| repo, token = os.getenv("STUDYHUB_DATASET"), os.getenv("HF_TOKEN") | |
| store = HfDatasetStore(repo, token) if repo else LocalStore(os.getenv("STUDYHUB_APPDATA", "appdata")) | |
| seed = {u: {"role": usr.role, "salt": usr.salt_hex, "hash": usr.hash_hex} | |
| for u, usr in parse_users(settings.app_users_raw).items()} | |
| users = UserStore(store, seed_admins=seed, invite_code=os.getenv("STUDYHUB_INVITE_CODE"), | |
| invites=InviteStore(store)) | |
| history = HistoryStore(store) | |
| from studyhub.web.ingest_worker import IngestWorker | |
| worker = IngestWorker(service, index_dir=os.environ.get("STUDYHUB_INDEX_DIR", "index"), | |
| materials_dir=os.environ.get("STUDYHUB_MATERIALS_DIR", "originals"), | |
| dataset_repo=repo or "", hf_token=token or "") | |
| worker.start() | |
| # Any upload that arrived while the Space was down gets ingested on boot. | |
| worker.boot_reconcile(store.list_files("uploads/")) | |
| secret = os.getenv("STUDYHUB_SESSION_SECRET") or token or "dev-secret-change-me" | |
| static = str(Path(__file__).parent / "static") | |
| return create_app(service, users, history, session_secret=secret, static_dir=static, | |
| dataset_name=repo or "", decks=DeckStore(store), notes=NotesStore(store), | |
| ingest=worker) | |
| def main() -> None: | |
| import uvicorn | |
| uvicorn.run(build_app(), host="0.0.0.0", port=int(os.getenv("PORT", "7860"))) | |
| if __name__ == "__main__": | |
| main() | |