studyhub-app / studyhub /web /server.py
parhamkhoshsolat's picture
Study features + Academy theme + threads + invite links + auto-ingest
981881b verified
Raw
History Blame Contribute Delete
3.49 kB
"""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()