CoolFace
Apppublic

HK44/remote-work-study-satisfaction

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
App README

Remote Work Study, Satisfaction

A data product for exploring and predicting remote work satisfaction from the Kaggle Remote Work and Mental Health dataset.

Live demo: https://huggingface.co/spaces/HK44/remote-work-study-satisfaction

Quick start:

docker compose up

Open http://localhost:8501 in your browser. The FastAPI service runs on port 8000 and is used by the app, which doesn't need to be normally hit directly.

To enable the LLM agent (WFHelper page), copy .env.example to .env and add your Anthropic API key before starting.

What the data shows:

The target (Satisfaction_with_Remote_Work) is essentially independent of every feature in this synthetic dataset. I triangulated this five ways in notebooks/rwss_eda.ipynb: Cramer's V, eta squared, a random forest baseline, feature-to-feature correlations, and categorical cross-associations. All agree. The model performs at around 33% accuracy, which is chance on three balanced classes.

The product acknowledges this honestly throughout. Rather than dress up weak predictions as strong ones, the UI surfaces the baseline comparison at every turn and flags the result as demonstration, not decision support.

Architecture:

Three parts. A FastAPI service (src/rwss/api/) is the single source of truth for every number the UI shows. A Streamlit app (src/rwss/app/) has five pages: Home, Explore, Model, Predict, Evaluate, plus WFHelper. An LLM agent (src/rwss/agent/) answers natural-language questions by calling the API as its tool layer, so it never hallucinates numbers.

A file-based model registry in runs/ tracks trained models. Each training writes a manifest.json with git SHA, data hash, hyperparameters, and metrics. A runs/CURRENT file points to the active model. The Model page in the UI switches between runs and hot-reloads the API.

Design decisions:

FastAPI + Streamlit + Docker, not a single-framework alternative. I've shipped this stack before in a prior project, so the operational risk was low. The separation of concerns (API owns model and data, app owns UI, agent talks to API like any other client) made the LLM agent straightforward to slot in later.

Logistic regression, not gradient boosting. The EDA showed there's no signal to learn. A simple model is the correct answer. I confirmed this by running a 200-tree random forest and it tied with the dummy baseline at 0.335.

No SHAP. The model is a logistic regression, so per-feature contributions are just the coefficients multiplied by the feature values. I wrote that directly in src/rwss/models/explain.py instead of using SHAP, which would have been an approximation library for a value we can compute exactly, and which pulls in a lot of unrelated dependencies.

Local deployment, not cloud-native. I felt that for this task a GCP/AWS infra would be over-engineering. The docker compose up story is honest about the problem's scale. I discuss how this would change in "Future work" below.

LLM agent uses tool calls, not context stuffing. The model never sees the data. It has seven tools mapped to API endpoints, so when the user asks a question, the model calls tools, the code runs them against real state, and the model phrases the answer. This prevents hallucination by construction.

AI usage:

I used Claude as a coding assistant throughout, primarily for boilerplate (Dockerfile structure, Pandera schema, test scaffolding) and for learning the Anthropic tool-use API which I hadn't used before. Design decisions and architecture are my own, including the "honest null result" product framing which I arrived at after the EDA showed no signal.

Layout:

src/rwss/
├── data/        schema (pandera), loader
├── features/    split, preprocessing
├── models/      training, registry, explainability
├── evaluation/  metrics, fairness, baselines
├── api/         fastapi service
├── app/         streamlit pages
├── agent/       llm tool-use agent
└── cli.py       typer cli

Commands:

rwss train                # train a new model, set as active
rwss serve                # run the fastapi server
rwss app                  # run the streamlit app
rwss predict <file.json>  # predict from a json file

Tests and CI:

Five tests in tests/test_main.py cover schema validation, data loading, training end-to-end, and API prediction. Data-dependent tests skip cleanly in CI when the CSV isn't present. Workflow in .github/workflows/ci.yml.

Hurdles:

A couple of hurdles faced along the way. The data's total lack of signal forced a product rethink from "predictor and explainer" to "here is the honest picture and the evidence for it." And Hugging Face Spaces' single-container constraint vs the local two-container compose setup here, whhich I solved by keeping the compose file for local dev and having the image's default CMD run a single-container startup script (scripts/start.sh).

Future possible work for a larger scale and data:

  • Proper experiment tracking (MLflow, DVC) instead of the file registry
  • Held-out test set with a permanent train/val/test split
  • Drift monitoring for production serving
  • Cloud deploy with autoscaling, infrastructure as code via Terraform, and proper observability (Datadog, Sentry, etc.)

Data:

Kaggle Remote Work and Mental Health by Waqar Ali. Permissive license, synthetic.