Skip to main content

topiclayers

From posts to topical multilayer networks — hardened and social-scientist-friendly.

Quickstart

# Requires Python 3.12
pip install topiclayers

# copy runnable examples (configs + toy data) into ./examples/
topiclayers init

topiclayers run examples/generic.yml

That's it. You get a GML network file in ./out/generic_toy/networks/.

What does it do?

  1. Loads your posts (Twitter JSONL, CSV, Parquet).
  2. Cleans text (removes URLs, @mentions, newlines).
  3. Models topics using BERTopic with SentenceTransformer embeddings.
  4. Labels topics with an LLM (local via Ollama by default) and propagates topic labels through retweet chains.
  5. Builds networks: single-layer retweet, multilayer per-topic, and bipartite temporal-text networks.

Minimal config

Save this as my_config.yml:

input:
  format: csv_posts
  posts: my_data.csv

name: my_dataset

topic_model:
  embedder: all-MiniLM-L6-v2
  min_topic_size: 50

network:
  type: multilayer_repost

output_dir: ./out/my_dataset

Run it: topiclayers run my_config.yml

Checking progress

Long runs write a live status file to <output_dir>/run_status.json. Check the current stage, elapsed time, and ETA from another terminal without touching the running job:

topiclayers status out/my_dataset

Example output:

Stage 3/7: embed
Status: running
Run: my_dataset
Progress: 412000/1200000 (34%)
Stage elapsed: 18m 12s
Stage ETA: ~35m 20s
Total elapsed: 21m 05s

Stages are load → data → embed → topic_model → label → network → manifest. Stages with a per-item counter (data, embed, network) report a live ETA. Opaque stages (BERTopic's UMAP+HDBSCAN) fall back to the median duration of past runs, stored in <output_dir>/stage_timings.json. While running, the terminal itself shows a live progress line (spinner, counter, ETA, elapsed time) that keeps ticking even in stages without a counter, plus a per-stage duration summary when the run finishes.

Topic labeling with an LLM (optional)

After clustering, the pipeline can ask a local LLM to write one short, readable label per topic (instead of raw keyword lists like -1_proclamation_plante_trending). Default is Ollama — free, local, nothing leaves your machine:

# one-time setup
pip install 'topiclayers[labeling]'
ollama pull qwen2.5:7b

# start the server in another terminal
ollama serve

Then just run the pipeline as usual (label_model is on by default). Any LiteLLM model string works:

topic_model:
  label_model: ollama/qwen2.5:7b      # default
  # label_model: gpt-4o-mini          # OpenAI (needs OPENAI_API_KEY)
  # label_model: anthropic/claude-3-haiku-20240307
  # label_model: ""                   # disable labeling

Custom / self-hosted OpenAI-compatible endpoints

Any server speaking the OpenAI protocol (Unsloth, llama.cpp, vLLM, LM Studio...) works via label_api_base:

topic_model:
  label_model: openai/unsloth/Qwen3.8-27B-GGUF   # note the openai/ prefix
  label_api_base: http://localhost:8888/v1

with the token in .env (key resolution order: LABEL_API_KEYOPENAI_LIKE_API_KEYOPENAI_API_KEY). You can also set LABEL_API_BASE in .env instead of the YAML. Find the exact model name your server exposes with curl http://localhost:8888/v1/models.

Labeling is non-fatal: if the model server is unreachable, topics keep their keyword labels and everything else proceeds normally.

Input formats

Format Extension Description
twitter_jsonl .json, .jsonl Twitter/X API v2 JSONL
csv_posts .csv Generic CSV with post_id, user_id, text columns
parquet_posts .parquet Same schema as CSV, Parquet format

CSV optional columns: created_at, lang, interaction_type (original/repost/quote/reply), target_post_id, mentions (semicolon-separated), extra_* passthrough columns.

What if something fails?

Symptom Likely cause Fix
"All topics are -1" / "no topics found" min_topic_size too high or dataset too small Halve min_topic_size in config, or use a larger dataset (>100 posts)
"Module not found" topiclayers not installed pip install topiclayers
topiclayers: command not found installed in a venv that isn't active Activate the venv (source .venv/bin/activate) or use python -m topiclayers.cli; on install with --user add ~/.local/bin to PATH
"OpenAI API key not set" Using OpenAI embedder without key Switch embedder to all-MiniLM-L6-v2 (default, works offline)
"Qdrant connection refused" Qdrant vector DB not running Ignore — Qdrant is optional. Set QDRANT_URL in .env to enable
"Cannot create multilayer network" All posts are outliers Reduce min_topic_size or provide more data
"UMAP spectral layout failed" Dataset too small (<10 posts) Topic modeling needs more data; consider using topic labels from elsewhere

Output files

For a dataset named <name> (e.g. my_dataset), output goes to <output_dir>/:

<output_dir>/
├── run_manifest.json              # Reproducibility metadata
├── run_status.json                # Live stage/ETA tracking (while running)
├── stage_timings.json             # Per-stage durations for ETA prediction
└── networks/
    ├── <name>_retweet.gml                  # Single-layer retweet network
    ├── <name>_retweet_network_ml.gml       # Multilayer (uunet format)
    ├── <name>_ttt.gml                      # Temporal-text bipartite network
    └── projected/
        └── <name>__prj_<topic>.gml         # Per-topic projected networks

Reusable artifacts (processed data, embeddings, the BERTopic model) go to the cache, not the output dir. By default the cache lives in a cache/ folder next to the input data file, so it persists across runs regardless of output_dir and can be shared between configs (files are prefixed with the dataset name). Override the location with cache_dir: in the config:

<cache_dir>/
├── data/
│   ├── tweets_<name>.pkl/.csv          # Full tweet table
│   ├── retweet_labeled_<name>.pkl/.csv # Retweets with topic labels
│   └── manifest_<name>.json            # Cache validity key
└── tm/<embedder_name>/
    ├── embeddings_<name>.pkl           # Document embeddings
    ├── topics_<name>.csv               # Topic table (with LLM labels)
    └── model_<name>/                   # BERTopic safetensors dir

Requirements

  • Python 3.12 (uunet, used for multilayer networks, does not ship wheels for 3.13+ yet)
  • Optional: Ollama + topiclayers[labeling] extra (LLM topic labeling), Docker (for Qdrant vector search), OpenAI API key (for OpenAI embeddings)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

topiclayers-0.3.0.tar.gz (33.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

topiclayers-0.3.0-py3-none-any.whl (39.7 kB view details)

Uploaded Python 3

File details

Details for the file topiclayers-0.3.0.tar.gz.

File metadata

  • Download URL: topiclayers-0.3.0.tar.gz
  • Upload date:
  • Size: 33.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for topiclayers-0.3.0.tar.gz
Algorithm Hash digest
SHA256 48f821a603e84497dd7edaf59a72d81d87fca10709af5ff52165631fd0815acf
MD5 957444078ba93876abbb61378ec1d4a3
BLAKE2b-256 c47730706e5f0785fa67039e9b811cd16a8721054c74e0064b6056aa70ee8554

See more details on using hashes here.

Provenance

The following attestation bundles were made for topiclayers-0.3.0.tar.gz:

Publisher: publish.yml on alessiogandelli/topiclayers

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topiclayers-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: topiclayers-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 39.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for topiclayers-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 941c7e9abd4194da1230dcd296643cd843d813482116d870f9fdae50351c8ca1
MD5 02551c1958fa3f5d31cb9c4cd5d0080b
BLAKE2b-256 0c89cedf063084724de290fe65f7ff060dffba5c1b5629577fdcf811807b3d90

See more details on using hashes here.

Provenance

The following attestation bundles were made for topiclayers-0.3.0-py3-none-any.whl:

Publisher: publish.yml on alessiogandelli/topiclayers

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.1

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page