LLM-powered research tool for quantifying echo chamber dynamics in online communities through discourse analysis
Project description
ChamberCheck
An LLM-powered tool for analyzing echo chamber dynamics in online communities
ChamberCheck quantifies discourse patterns in online communities (Reddit, Facebook, etc.) by measuring argument diversity, hostility, deviation suppression, and epistemic openness. The tool provides both individual metrics and a composite "Echo Chamber Score" to help researchers and community moderators understand discourse health.
Features
- ๐ Multi-platform scraping - Modular architecture supports Reddit, Facebook, and other platforms
- ๐ Comprehensive metrics - Measures argument diversity, hostility, suppression, and epistemic closure
- ๐ง LLM-powered analysis - Uses large language models for nuanced discourse understanding
- ๐ Topic-conditional scoring - Evaluates echo chamber behavior across different subject domains
- ๐ฏ Research-grade methodology - Based on social epistemology and political psychology literature
Project Structure
ChamberCheck/
โโโ src/
โ โโโ ChamberCheck/
โ โโโ scrapers/ # Platform-specific data collection
โ โโโ analysis/ # LLM-powered discourse analysis
โ โโโ preprocessing/ # Data cleaning and filtering
โ โโโ CC_derived_metrics/ # Echo chamber metrics computation
โ โโโ model_analysis/ # A/B/n testing framework
โ โโโ reporting/ # Report generation
โ โโโ models/ # Data models (Post, Comment, etc.)
โ โโโ scoring/ # Metric aggregation
โ โโโ utils/ # Utilities and logging
โ โโโ config.py # Configuration management
โ โโโ constants.py # Project-wide constants
โโโ config/ # YAML configuration files
โ โโโ config.yaml # Production config
โ โโโ config.test.yaml # Test/dev config
โ โโโ config.intellectual.yaml # Custom config template
โโโ data/
โ โโโ raw/ # Raw scraped data
โ โโโ processed/ # Cleaned data
โ โโโ output/ # Analysis results and plots
โโโ test_scripts/ # Pipeline execution scripts
โ โโโ workflow.py # Full 8-stage pipeline runner
โ โโโ run_*.py # Individual stage executors
โ โโโ ad-hoc/ # Exploratory and diagnostic scripts
โโโ tests/ # Unit and integration tests
โโโ pyproject.toml # Package metadata and dependencies
โโโ ARCHITECTURE_RULES.md # Coding guidelines
โโโ README.md # This file
Installation
Prerequisites
- Python 3.9 or higher
- Reddit API credentials (for Reddit scraping)
Setup
- Clone the repository:
git clone https://github.com/yourusername/ChamberCheck.git
cd ChamberCheck
- Create a virtual environment:
# On Windows (PowerShell)
python -m venv venv
.\venv\Scripts\Activate.ps1
# On Linux/Mac
python -m venv venv
source venv/bin/activate
- Install the package with dependencies:
# Install in editable mode with all dependencies
pip install -e .
# Or install with development tools
pip install -e ".[dev]"
- Configure API credentials:
Option A: Environment Variables (Recommended)
Set environment variables before running ChamberCheck:
# Windows PowerShell
$env:REDDIT_CLIENT_ID = "your_reddit_client_id"
$env:REDDIT_CLIENT_SECRET = "your_reddit_client_secret"
$env:REDDIT_USER_AGENT = "ChamberCheck/0.1"
$env:OPENAI_API_KEY = "your_openai_api_key"
$env:ANTHROPIC_API_KEY = "your_anthropic_api_key"
# Linux/Mac
export REDDIT_CLIENT_ID="your_reddit_client_id"
export REDDIT_CLIENT_SECRET="your_reddit_client_secret"
export REDDIT_USER_AGENT="ChamberCheck/0.1"
export OPENAI_API_KEY="your_openai_api_key"
export ANTHROPIC_API_KEY="your_anthropic_api_key"
Option B: Local .env File (Development Only)
Create a .env file in the project root (already .gitignored):
REDDIT_CLIENT_ID=your_reddit_client_id
REDDIT_CLIENT_SECRET=your_reddit_client_secret
REDDIT_USER_AGENT=ChamberCheck/0.1
OPENAI_API_KEY=your_openai_api_key
ANTHROPIC_API_KEY=your_anthropic_api_key
Option C: User-Level Config (Reusable Across Projects)
Create ~/.chambercheck/config.yaml:
reddit:
client_id: your_reddit_client_id
client_secret: your_reddit_client_secret
user_agent: ChamberCheck/0.1
post_analysis:
provider: openai # or anthropic
model: gpt-4o # or claude-3-5-sonnet-20241022
comment_analysis:
provider: anthropic
model: claude-haiku-4-5-20251001
Usage: The 8-Stage Pipeline
ChamberCheck implements a modular 8-stage pipeline for analyzing discourse:
Overview
| Stage | Name | Input | Output | Module |
|---|---|---|---|---|
| 1 | Scrape Posts | Subreddit config | posts.json |
scrapers.batch_scrape_posts_only() |
| 2 | Analyse Post Titles | Posts | analysis_NNN.json |
analysis.analyze_posts() |
| 3 | Preprocess Posts | Posts + Analysis | pre_process_NNN.json |
preprocessing.preprocess_posts() |
| 4 | Scrape Comments | Filtered posts | comments_*.json |
scrapers.scrape_comments() |
| 5 | Preprocess Comments | Comments | comments_filtered_*.json |
preprocessing.preprocess_comments() |
| 6 | Analyse Comments | Filtered comments | comment_analysis_*.json |
analysis.run_comment_analysis() |
| 7 | Compute Metrics | Analyzed comments | v3_metrics_*.json |
CC_derived_metrics.V3Metrics |
| 8 | Visualize | Metrics | PNG plots | Ad-hoc plotting scripts |
Running the Full Pipeline
The simplest way to run all 8 stages:
python test_scripts/workflow.py
Edit test_scripts/workflow.py to configure:
CONFIGโ path to YAML config file (default:config/config.test.yaml)SCRAPE_DIRโ skip scraping by pointing to existing data folder- Comment/uncomment stages to run selectively
Running Individual Stages
Stage 1: Scrape Posts
python test_scripts/run_scraper_posts.py
Stage 2: Analyse Post Titles
python test_scripts/run_analyze_posts.py
Stage 3: Preprocess Posts
python test_scripts/run_preprocess_posts.py
Stage 4: Scrape Comments
python test_scripts/run_scrape_comments.py
Stage 5: Preprocess Comments
python test_scripts/run_preprocess_comments.py
Stage 6: Analyse Comments
python test_scripts/run_analyze_comments.py
Stage 7: Compute Metrics
python test_scripts/run_v3_metrics.py
Stage 8: Generate Plots
python test_scripts/ad-hoc/plot_v3_metrics.py
Configuration
All pipeline parameters are in YAML config files under config/:
scraping:
subreddits: ["politics", "atheism", "philosophy"] # Which communities to scrape
num_posts: 100 # Posts per subreddit
sort_method: "top" # Sorting: top, new, hot
time_filter: "all" # Time range: all, year, month, week, day
post_analysis:
provider: "anthropic" # LLM: anthropic or openai
model: "claude-3-haiku-20240307" # Model name
temperature: 0.1 # Creativity: 0=deterministic, 1=random
max_tokens: 500 # Output token limit
preprocessing:
min_comments: 10 # Posts must have โฅ10 comments
top_n_per_subreddit: 30 # Select top-30 posts per community
min_discussion_score: 0.6 # Discussion quality threshold
min_topic_peers: 1 # Minimum peer comments for topic validation
comment_scraping:
max_comments_per_post: 500 # Max comments to fetch per post
Example: Custom Analysis
from chambercheck import Config
from chambercheck.CC_derived_metrics import V3Metrics
import json
# Load configuration
config = Config(config_path="config/config.test.yaml")
# Load computed metrics
metrics = V3Metrics.from_files(
metric_file="data/output/scrape_001/v3_metrics_001.json"
)
# Inspect echo chamber score per subreddit
for subreddit, scores in metrics.by_subreddit.items():
print(f"{subreddit}: Echo Argument Score = {scores['echo_argument_score']:.3f}")
For detailed methodology and metric definitions, see PIPELINE_WORKFLOW.md.
A/B/n Testing Different LLM Models
ChamberCheck supports A/B/n testing to compare how different LLM models or configurations analyze the same comments. This is useful for evaluating model performance on discourse analysis tasks.
Workflow
- Generate A/B/n test set: Select 50 representative comments with their reply chains from scraped data
- Export prompts: Create consistent prompt files for comparison
- Run multiple analyses: Test different models (e.g., gpt-4o vs claude-3.5-sonnet) on the same prompts
- Compare results: Analyze differences in metric scores across models
Step 1: Generate A/B/n Test Set
from chambercheck.analysis import generate_abn_test_set
result = generate_abn_test_set(
raw_folder_path="data/raw/scrape_001",
num_comments=50, # Target total comments (including replies)
random_seed=42, # Optional: for reproducibility
)
# Result includes:
# - prompt_file: abn_test_prompts_001.txt
# - metadata_file: abn_test_prompts_metadata_001.json
# - random_seed: seed used for reproducibility
Or use the test script:
python test_scripts/run_abn_test_builder.py
Understanding the A/B/n Test Structure
Comment Selection Algorithm:
- Randomly selects ~50 top-level comments from the specified post
- For each selected comment, follows the reply chain by taking the most upvoted reply at each level
- Creates chains until no more replies exist (no branching, just linear chains)
- Stores comment IDs and chain structure in metadata
Output Files:
-
abn_test_prompts_001.txt - Raw text file containing all prompts exactly as LLMs will see them
- Each prompt separated by
=line - Shows parent comment context followed by the target comment
- Each prompt separated by
-
abn_test_prompts_metadata_001.json - Metadata file containing:
random_seed: Seed used for this run (for reproducibility)selected_comment_ids: List of all 50 comment IDs in ordercomment_positions: Position of each comment in its chain (0 = top-level)source_file: Original raw data filechains_breakdown: How many comments per chain
Step 2: Run Analysis on A/B Test Set
After generating the A/B test set with model A, switch models and run the same analysis:
from chambercheck.analysis import batch_analyze_comments
# Run analysis with model A (e.g., gpt-4o)
metadata_a = batch_analyze_comments(
comment_files=["path/to/extracted/from/abn_test.json"],
limit=50,
model_name="gpt-4o",
)
# Output: data/output/abn_test/abn_test_analysis_001_001.json
# Switch to model B and run again
metadata_b = batch_analyze_comments(
comment_files=["path/to/extracted/from/abn_test.json"],
limit=50,
model_name="claude-3-5-sonnet-20241022",
)
# Output: data/output/abn_test/abn_test_analysis_001_002.json
File Naming Convention
-
Prompts:
abn_test_prompts_XXX.txt+abn_test_prompts_metadata_XXX.jsonXXX: Prompt set number (001, 002, etc.)
-
Analysis:
abn_test_analysis_XXX_YYY.json+abn_test_analysis_metadata_XXX_YYY.jsonXXX: Prompt set number (which prompts were used)YYY: Analysis run number for that prompt set (001, 002, etc.)
Example: abn_test_analysis_001_002.json = Second analysis run using prompt set 001
Comparison Example
import json
# Load results from different models
with open("data/output/abn_test/abn_test_analysis_001_001.json") as f:
results_gpt4o = json.load(f)
with open("data/output/abn_test/abn_test_analysis_001_002.json") as f:
results_claude = json.load(f)
# Compare average scores
for comment_gpt4, comment_claude in zip(results_gpt4o, results_claude):
gpt_stance = comment_gpt4["topic"]["stance"]["value"]
claude_stance = comment_claude["topic"]["stance"]["value"]
if gpt_stance != claude_stance:
print(f"Stance difference for {comment_gpt4['comment_id']}: "
f"GPT4o={gpt_stance}, Claude={claude_stance}")
Methodology
ChamberCheck decomposes echo chambers into measurable dimensions:
Base Metrics
- Argument Diversity: Semantic clustering and novelty of arguments
- Deviation Suppression: Treatment of dissenting viewpoints
- Hostility: Personal attacks and ad hominem density
- Epistemic Openness: How evidence and external sources are handled
- Identity Policing: Boundary enforcement based on group membership
Composite Scores
- Civility Score: Combines hostility and ad hominem metrics
- Epistemic Health Score: Measures openness to evidence
- Discourse Pluralism Score: Evaluates argument diversity and tolerance
Echo Chamber Score
Weighted composite of low pluralism, high suppression, high hostility, and low epistemic openness.
Topic-Conditional Analysis
ChamberCheck evaluates discourse across different subject domains, recognizing that communities may be open on some topics while defensive on others (e.g., sports vs. politics).
Testing & Development
Running Tests
# Run all tests with coverage
pytest tests/ -v
# Run specific test file
pytest tests/test_workflow.py -v
# Run with coverage report
pytest --cov=ChamberCheck tests/
Pipeline Validation
The tests/test_workflow.py module validates that all 8 pipeline stages are correctly wired:
pytest tests/test_workflow.py::TestStage1Imports -v
pytest tests/test_workflow.py::TestWorkflowOrdering -v
Code Quality
# Format code
black src/ tests/
# Lint
flake8 src/ tests/
# Type checking
mypy src/
Installing in Development Mode
# Install package + dev tools
pip install -e ".[dev]"
# Reinstall after changes to setup metadata
pip install --force-reinstall -e .
Making the Package Importable
Once installed, you can use ChamberCheck like any Python package:
# Both import styles work:
from chambercheck import Config
from ChamberCheck.scrapers import batch_scrape_posts_only
Documentation
For deeper technical documentation:
- ARCHITECTURE_RULES.md โ Coding standards and project conventions
- PROJECT_STRUCTURE.md โ Detailed module documentation
- PIPELINE_WORKFLOW.md โ Full 8-stage pipeline explanation
- PLOTS_DOCUMENTATION.md โ Visualization methodology
Research & Citations
This tool is based on academic research in social epistemology, political psychology, and computational social science. Key concepts include:
- Echo chamber operationalization (Cota et al., 2019)
- Embedding-based discourse metrics (Alatawi et al., 2023)
- Hostility and intergroup dynamics (Efstratiou et al., 2022)
- Topic-conditional analysis (various sources)
Ethics & Limitations
- Privacy: User identities are anonymized; no longitudinal tracking
- Bias: LLM-based metrics require validation against human annotations
- Interpretation: Scores reflect observable discourse, not internal beliefs
- Comparison: Results should be interpreted comparatively, not as absolute judgments
Getting Help
API Issues?
- Check your API key is set correctly (env var or
.envfile) - Verify you have sufficient credits/quota with the LLM provider
- See
ARCHITECTURE_RULES.mdfor credential management best practices
Pipeline Problems?
- Check pipeline stage outputs are in the expected locations
- Verify configuration in
config/*.yamlmatches your environment - See
PIPELINE_WORKFLOW.mdfor detailed stage-by-stage troubleshooting
Questions?
- Open an issue on GitHub
- Check existing issues and discussions
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with tests (run
pytestbefore submitting) - Follow code style:
black src/(line length 100) - Submit a pull request
See ARCHITECTURE_RULES.md for detailed guidelines.
License
MIT License - see LICENSE file for details
Contact
For questions or collaboration inquiries, please open an issue on GitHub.
Note: This project is research-grade software under active development. API signatures and data formats may change between releases. See CHANGELOG.md (if present) for version history.
License: MIT โ See LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chambercheck-0.1.0.tar.gz.
File metadata
- Download URL: chambercheck-0.1.0.tar.gz
- Upload date:
- Size: 135.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a97f2ca24cbd05b329fc6a335153d92f20841deebeba355da2e415b7d1149b2
|
|
| MD5 |
813291cb59a2199678ab4c1ccd78cb33
|
|
| BLAKE2b-256 |
b26854c07bea3ca75860f85ec2be227b18eb9100c56af3147f96cc2ee276977d
|
File details
Details for the file chambercheck-0.1.0-py3-none-any.whl.
File metadata
- Download URL: chambercheck-0.1.0-py3-none-any.whl
- Upload date:
- Size: 136.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
392834590311fb22007b20f9bc8d2d9beb643b4e859fab1de00701628a2f6503
|
|
| MD5 |
15ef970a02c879f686ae0bb02c7854b3
|
|
| BLAKE2b-256 |
c5fce04592553a46f33ade1f1e0129fd0e0166c33090ba5a2b5f2c116e85a937
|