Monitor and filter Fediverse hashtags, curate quality content, and distribute via external tools like Zhongli
Project description
FenLiu (分流)
Created by marvin8 with assistance from DeepSeek AI assistant.
⚠️ DISCLAIMER / PROVISO: This project is a work in progress with major changes still happening. It is in no way anywhere close to finished and is only borderline useful for actual production use. Expect breaking changes, incomplete features, and significant architectural evolution as development continues.
Divide the Fediverse content flow
FenLiu is a web application that monitors Fediverse hashtags, filters spam, allows human review, learns from feedback, and exports quality content for boosting. Inspired by the ancient Chinese Dujiangyan irrigation system (256 BC) that separated silt from water, FenLiu applies 2,300-year engineering wisdom to modern digital content streams.
Current Status (1 March 2026) — v0.2.3
✅ Phase 1: Foundation & MVP - COMPLETE
- Web Application: PyView-based LiveView interface with real-time capabilities
- Fediverse Integration: Fetch posts from Mastodon/Fediverse instances
- Database: SQLAlchemy models with SQLite backend, optimized with eager loading
- REST API: Full CRUD operations for all entities with proper HTTP semantics
- Testing: Comprehensive test suite with 267 tests passing
✅ Phase 2: Enhanced Features - COMPLETE
- Spam Scoring: Advanced rule-based system (0-100 scale) with 7 detection rules
- Streams Management: Full CRUD operations with bulk fetch and progress tracking
- UI Consistency: All pages with consistent styling and hyperlinked hashtags
- Manual Review Interface: Complete web interface for reviewing posts with approve/reject workflow
- Learning System Foundation: ReviewFeedback model for historical tracking of review decisions
- Export Foundation: Database schema and API support for Curated Queue integration
- Alembic Migrations: Full Alembic setup with baseline migration;
alembic upgrade headruns automatically on startup - DB Session Management: All database sessions now properly closed via
@contextmanageronget_db() - Refined Review Interface: Enhanced review page with improved styling and user experience
- Dynamic Version Management: Application version automatically loads from package metadata
📋 Phase 3: Advanced Functionality - PLANNED
- Export Implementation: Complete Curated Queue export functionality
- Machine Learning Integration: Train models on collected review feedback
- Real-time Features: Enhanced LiveView for instant updates
- Multi-instance Support: Monitor multiple Fediverse instances simultaneously
- Advanced Filtering: Custom rule system for content classification
Recent Progress (March 2026 - Version 0.2.3)
Bug Fixes & UX Improvements (v0.2.3 — 1 March 2026)
- No JavaScript Popups: All
alert(),confirm(), andprompt()calls removed from every template; replaced with inline flash messages and page redirectsdashboard.html:addNewStream()(which usedprompt()) replaced with direct links to/streams;fetchStream()errors shown viashowFlash()hashtag_streams.html: Allalert()calls replaced with ashowFlash()helper;confirm()before "Fetch All" removed (the progress modal provides sufficient feedback)reblog_controls.html:confirm()guards removed fromdeleteBlockedUser()anddeleteBlockedHashtag()(trash icon already signals intent)
- Auto-Reject on Fetch Fixed: Posts fetched from Fediverse were not being auto-rejected even when the setting was enabled. Root cause: the SQLAlchemy session uses
autoflush=False, so newlyadd()-ed posts were invisible to theSELECTinsidereject_blocked_posts(). Fixed by callingdb.flush()after all new posts are staged in_save_fetched_posts(). - New Regression Tests: Three tests added covering auto-reject by blocked user, auto-reject by blocked hashtag, and no-reject when the setting is disabled.
Code Quality & Bug Fixes (v0.2.1 — 1 March 2026)
- DB Session Leak Fixed:
get_db()decorated with@contextmanager; all 23 call sites updated towith get_db() as db: - FediverseClient Leak Fixed:
httpx.AsyncClientnow closed viatry/finallyafter each fetch - Routing Bug Fixed:
/posts/batch-scoreroute moved before/{post_id}to prevent shadowing load_stats()Performance: Replacedlen(all())counts withfunc.count()SQL aggregates- Alembic Setup:
alembic.ini,alembic/env.py,alembic/script.py.makocreated; baseline migration generated and stamped; app lifespan now runsalembic upgrade headon startup - Request Type Hints: All API handler
requestparameters now typed asRequest - Ruff Clean: All linting issues resolved across production and migration code
Manual Review Interface
- Complete Review Workflow: Approve/reject decisions with scoring adjustment
- Review Feedback Tracking: Historical tracking of review decisions for future ML training
- Refined Review Interface: Enhanced styling and user experience improvements
- Dynamic Version Management: Application version now automatically loads from package metadata
- Test Expansion: Increased test coverage from 159 tests to current suite
- Interactive Scoring: Manual score adjustment with detailed breakdown visualization
- Real-time Stats: Dashboard cards showing review progress and statistics
- Filter System: Filter posts by spam score range and hashtag streams
Streams Management Enhancement
- Complete CRUD Operations: Create, Read, Update, Delete for hashtag streams with modal dialogs
- Bulk Fetch Functionality: Fetch all active streams simultaneously with real-time progress tracking
- API Consistency: Fixed endpoint mismatches and HTTP 204 response handling
- Performance Optimizations: Eager loading of relationships to prevent N+1 queries
User Interface Improvements
- Consistent Styling: All pages now display hyperlinked hashtags matching dashboard behavior
- Dashboard Analytics: Charts for posts over time and top hashtags visualization
- Responsive Design: Fully responsive across desktop, tablet, and mobile devices
- Real-time Feedback: Button state management with spinners during operations
- Enhanced Navigation: Improved mobile menu and accessibility features
Technical Foundation
- Testing: All 267 tests passing with comprehensive coverage
- Type Safety: Enhanced type annotations throughout the codebase
- Code Quality: Pre-commit hooks passing (ruff format, ruff check)
- Performance: Optimized database queries and eager loading
- Version Management: Dynamic version loading from package metadata
Quick Start
Prerequisites
- Python 3.11 or higher
uvpackage manager (recommended)
Installation
# Install dependencies
uv sync -U --all-groups
# Optional: Set up pre-commit hooks
uv run pre-commit install
Running the Application
# Development mode with auto-reload (simpler)
fenliu --reload --debug
# Alternative development mode
uv run python -m fenliu --reload --debug
# Production mode (simpler)
fenliu --host 0.0.0.0 --port 8000
# Alternative production mode
uv run python -m fenliu --host 0.0.0.0 --port 8000
# See all options
uv run fenliu --help
Debug Logging
Enable detailed debug logging to file with the --debug flag. This writes all DEBUG level logs to logs/fenliu_debug.log with module name, function name, and line number context. Console output shows INFO and ERROR only. Log files rotate daily at midnight with 3 versions retained.
# Enable debug logging
python -m fenliu --debug
# View logs in real-time
tail -f logs/fenliu_debug.log
# Use custom log directory
python -m fenliu --debug --log-dir=/var/log/fenliu
In your code, use from fenliu.logging import get_logger to add debug entries: logger = get_logger(__name__) then logger.debug(f"context: message with {variable}").
First Steps
- Start the server:
fenliu --reload(oruv run python -m fenliu --reload) - Open browser: Navigate to
http://localhost:8000 - Add a hashtag: Go to Streams page and add a hashtag (e.g., "python")
- Fetch posts: Click "Fetch" on the hashtag stream (or use "Fetch All" for bulk operations)
- Review posts: Use the Manual Review interface to approve quality content or reject spam
API Usage
Basic Examples
# List all hashtag streams
curl http://localhost:8000/api/v1/hashtags
# Add a new hashtag stream
curl -X POST http://localhost:8000/api/v1/hashtags \
-H "Content-Type: application/json" \
-d '{"hashtag": "python", "instance": "mastodon.social", "active": true}'
# Fetch posts for a stream (individual or bulk)
curl -X POST http://localhost:8000/api/v1/hashtags/1/fetch?limit=20
# Update a stream
curl -X PATCH http://localhost:8000/api/v1/hashtags/1 \
-H "Content-Type: application/json" \
-d '{"active": false}'
# Get application statistics
curl http://localhost:8000/api/v1/stats
# Review a post (approve)
curl -X PATCH http://localhost:8000/api/v1/posts/123 \
-H "Content-Type: application/json" \
-d '{"approved": true, "reviewer_notes": "High-quality content"}'
# Adjust spam score manually
curl -X PATCH http://localhost:8000/api/v1/posts/123 \
-H "Content-Type: application/json" \
-d '{"manual_spam_score": 15, "reviewer_notes": "Adjusted score based on context"}'
API Endpoints
GET /api/v1/hashtags- List all hashtag streams with filteringPOST /api/v1/hashtags- Create new streamGET/PATCH/DELETE /api/v1/hashtags/{id}- Stream CRUD operationsPOST /api/v1/hashtags/{id}/fetch- Fetch posts for specific streamGET /api/v1/posts- List posts with advanced filtering (stream, spam score, status, reviewed, approved, exported)GET /api/v1/posts/{id}- Get specific post detailsPATCH /api/v1/posts/{id}- Update post (review, approve, adjust scores)GET /api/v1/stats- Application statistics and metricsGET /health- Health check endpointGET /info- Application informationGET /api/v1/posts/{id}/score- Get post scoring analysisPOST /api/v1/posts/{id}/recalculate- Recalculate spam scorePOST /api/v1/posts/batch-score- Batch score multiple posts
Note: The
/postslisting page has been removed. Use the/reviewLiveView interface to browse and manage posts.
Project Structure
fenliu/
├── src/fenliu/
│ ├── __init__.py # Package definition
│ ├── __main__.py # CLI entry point
│ ├── main.py # PyView application with enhanced queries
│ ├── config.py # Application settings
│ ├── database.py # Database configuration
│ ├── models.py # SQLAlchemy models with relationships (including ReviewFeedback)
│ ├── schemas.py # Pydantic schemas for validation
│ ├── api/ # REST API endpoints (full CRUD with review support)
│ ├── services/ # Business logic (spam scoring, Fediverse client)
│ └── templates/ # HTML templates (dashboard, streams, review, stats, post_details)
├── alembic/ # Database migration scripts
│ ├── env.py # Alembic environment (wired to app config and models)
│ ├── script.py.mako # Migration file template
│ └── versions/ # Migration history
├── alembic.ini # Alembic configuration
├── tests/ # Test suite (267 tests)
├── pyproject.toml # Project configuration
└── README.md # This file
Testing
# Run linting and formatting
ruff check src/fenliu/
ruff format src/fenliu/
# Run pre-commit checks
pre-commit run --all-files
# Run full test suite
pytest --cov=src/fenliu tests/
# Quick validation
python -m pytest -q
# Database migrations
alembic upgrade head # apply all pending migrations
alembic revision --autogenerate -m "add column" # generate a new migration
alembic current # show current revision
alembic history # list all revisions
Configuration
Environment variables (via .env file):
# Database configuration
DATABASE_URL=sqlite:///./fenliu.db
# Fediverse settings
DEFAULT_INSTANCE=mastodon.social
API_TIMEOUT=30
MAX_POSTS_PER_FETCH=20
RATE_LIMIT_DELAY=1.0
# Application settings
DEBUG=false
SECRET_KEY=your-secret-key-change-in-production
APP_NAME=FenLiu
# APP_VERSION is read from package metadata — do not set this env var
# Spam scoring thresholds
VERY_HIGH_THRESHOLD=76
LOW_MAX_THRESHOLD=25
Development Workflow
After dependency changes:
uv sync -U --all-groups
Quick validation:
pre-commit run --all-files
Full validation before commits:
nox
Technical Stack
- Framework: PyView (Starlette-based LiveView) with real-time capabilities
- Database: SQLAlchemy with SQLite, optimized with eager loading
- API Client: minimal-activitypub for Fediverse integration
- Async/await: Full async support throughout the codebase except for interacting with SQLite db.
- Type Hints: Comprehensive type annotations with Pydantic validation
- Frontend: Jinja2 templates with Tailwind CSS and responsive design
- Testing: pytest with 267 tests covering all major functionality
- Linting/Formatting: ruff with pre-commit hooks
- Package Management: uv for fast dependency resolution
- Spam Scoring: Rule-based system with 7 detection rules (0-100 scale)
- Review System: Manual review interface with decision tracking
- Learning Foundation: ReviewFeedback model for future ML training
Cultural Context
The name "FenLiu" (分流) means "divide the flow" in Chinese, inspired by the ancient Dujiangyan irrigation system (256 BC). This project applies the same engineering wisdom to digital content streams, separating valuable content from spam and noise while maintaining the natural flow of community conversation.
Documentation
- Roadmap - 5-phase development plan with current progress
- Project Summary - Overview and detailed status
- LLM System Prompt - Development standards and guidelines
License
AGPL-3.0 License - See LICENSE file for details.
Contributing
- Follow the existing code style (ruff formatted with comprehensive type hints)
- Write tests for new functionality (maintain 100% test pass rate)
- Update documentation to reflect changes
- Run
noxbefore submitting changes - Run
alembic upgrade headafter pulling changes that include new migrations
Status: Phase 1 & 2 Complete ✅, Phase 3 Planned 📋 Version: 0.2.3 Date: 1 March 2026 Test Status: 267/267 tests passing ✅ Code Quality: All ruff and pre-commit checks passing ✅ Next Phase: Curated Queue API queue integration and ML training (Phase 3) Framework: PyView (Starlette-based LiveView) Architecture: Async Python with comprehensive type hints and modern web patterns Recent Focus: JS popup removal, auto-reject on fetch bug fix
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 fenliu-0.4.1.tar.gz.
File metadata
- Download URL: fenliu-0.4.1.tar.gz
- Upload date:
- Size: 405.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2b772730c981382cfd9ebf0ba7d8a8ff2918f92c895a5c0bd9fe070171b6785
|
|
| MD5 |
8d19739b15539d2523c84f4774537c36
|
|
| BLAKE2b-256 |
0143bcacd2959b5f286b44a1ff6850bd1dd4d7f96af1a8160c594a32ec744bc3
|
File details
Details for the file fenliu-0.4.1-py3-none-any.whl.
File metadata
- Download URL: fenliu-0.4.1-py3-none-any.whl
- Upload date:
- Size: 420.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8237f2d584103fa79aae4b7dc58ff6307f8ca9267c486f0a8190ceea3ecccdf4
|
|
| MD5 |
83e342f224beba8d86b8e304a7a0fe5c
|
|
| BLAKE2b-256 |
354d8f2eee8401a180c0fa131c57a18bc53aa48cb1472859c428fd3a506fb4b1
|