Skip to content

About

Streamlit application for sentiment classification in English text using SiEBERT on Apple Silicon with MLX.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

SiEBERT MLX

CI Release License: MIT Python

Streamlit application for sentiment classification in English text using SiEBERT on Apple Silicon with MLX.

SiEBERT MLX classifying sample data in dark mode

Features

  • Wide layout: upload, column picker and Classify/Reset in a sidebar, with the main area left to your data
  • Upload a CSV or try built-in sample data
  • Auto-detects text columns with manual override, and previews the whole file with the selected column first
  • Binary sentiment (positive/negative) with confidence scores
  • Summary metric cards: total rows, positive/negative counts, average confidence, plus a skipped count when the file has blank text cells, beside a sentiment-distribution chart
  • Styled results table with the prediction and confidence pinned to its left edge, and the CSV download in its header
  • Never overwrites your data: a CSV that already has a Sentiment or Confidence column keeps it, and the model's output is added as Sentiment (model) / Confidence (model)
  • Results persist across interactions; one-click Reset from every state a loaded file can reach
  • A custom dark theme — neutral graphite with one violet accent, so green and red stay reserved for sentiment — beside Streamlit's built-in light theme, switchable from the app menu
  • Batched MLX inference on Apple Silicon (float16 weights), length-sorted to cut padding waste
  • Handles empty, whitespace-only, and malformed input; text longer than 512 tokens is truncated

Requirements

  • Apple Silicon Mac (M1 or later) — required. MLX ships arm64-only macOS wheels, so the app will not install or run on Intel Macs, Linux, or Windows.
  • Python 3.12+
  • uv for dependency management

Setup

uv sync

The SiEBERT model is public, so no authentication is required. Optionally, set a Hugging Face token for higher download rate limits (or access to gated/private repos) — either export it or place it in a gitignored .env file (loaded automatically):

export HF_TOKEN=hf_...

Usage

uv run streamlit run streamlit_app.py

On first launch the SiEBERT model (~1.3 GB) is downloaded from Hugging Face and cached under ~/.cache/huggingface, so the initial Loading model... step can take a few minutes. Subsequent launches load from cache.

Sample Data

samples/ contains example CSVs:

  • mixed_sample.csv — 20-row mixed sample, loaded by the Sample button
  • product_reviews.csv, movie_reviews.csv, social_media.csv, restaurant_reviews.csv, app_reviews.csv — 40 rows each, one per domain
  • blank_cells.csv — 10-row edge-case sample with missing and whitespace-only cells in the text column

Testing

uv run pytest                              # unit + flow tests (integration skipped)
uv run pytest tests/test_streamlit_app.py  # unit tests
uv run pytest tests/test_app_flow.py       # AppTest flow tests
uv run pytest --integration                # + the real-checkpoint tests

Model loading is mocked everywhere except tests/test_inference_integration.py, which loads the real checkpoint and pins what the model actually computes — the weight/logit dtypes, the label mapping, and a few confidences. Those are skipped unless you pass --integration, because on a cold cache they download ~1.4 GB and convert it to safetensors.

Development

Lint, format, and type-check before committing:

uv run ruff check .          # lint
uv run ruff format --check . # format check
uv run ty check .            # type check

CI (.github/workflows/ci.yml) runs these same checks plus the test suite on macOS, then a second job runs the integration tests against the real checkpoint.

Releases

A third CI job publishes a GitHub Release automatically. Bumping [project].version in pyproject.toml cuts a public release once that commit passes both CI jobs on main — so treat a version bump as its own change, not something to fold into an unrelated PR. Release notes are generated from the commit and PR subjects since the previous tag, so keep those tidy.

The job is a no-op when a tag for the current version already exists, and a PEP 440 pre-release version (0.8.0rc1) is marked as a pre-release rather than becoming "Latest". To release without a version bump — re-cutting a deleted release, or tagging an older commit — push the tag by hand and .github/workflows/release.yml handles it:

git tag v0.8.0 && git push origin v0.8.0

Citation

If you use SiEBERT in your work, please cite the following paper:

Hartmann, J., Heitmann, M., Siebert, C., & Schamp, C. (2023). More than a Feeling: Accuracy and Application of Sentiment Analysis. International Journal of Research in Marketing, 40(1), 75-87.

@article{hartmann2023,
  title = {More than a Feeling: Accuracy and Application of Sentiment Analysis},
  journal = {International Journal of Research in Marketing},
  volume = {40},
  number = {1},
  pages = {75-87},
  year = {2023},
  doi = {https://doi.org/10.1016/j.ijresmar.2022.05.005},
  url = {https://www.sciencedirect.com/science/article/pii/S0167811622000477},
  author = {Jochen Hartmann and Mark Heitmann and Christian Siebert and Christina Schamp},
}

License

Released under the MIT License. This covers the application code in this repository only.

The SiEBERT model is downloaded at runtime and is subject to its own terms from its model card; it is not redistributed by this project.

About

Streamlit application for sentiment classification in English text using SiEBERT on Apple Silicon with MLX.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages