An intelligent multi-platform content generation system built with LangGraph, featuring human-in-the-loop review, image generation, and comprehensive observability.
This project includes 6 specialized agent definitions to help complete development with mastery. Each agent handles a specific phase with clear responsibilities, patterns, and success criteria.
π Quick Start: See .claude/AGENT_QUICK_START.md
π Agent Details: See .claude/agents/README.md
ποΈ Architecture Guide: See CLAUDE.md
Current Phase: Database Implementation (Phase 3) β Use database-tdd-agent
This project is a learning-focused implementation of an agentic AI system that generates optimized social media content for LinkedIn, Instagram, and WordPress. It demonstrates modern AI engineering practices including:
- Agentic Workflows: LangGraph state machines with conditional routing
- Human-in-the-Loop: Checkpointing and approval workflows
- Multi-Modal Generation: Text and image content creation
- LLM Resilience: Intelligent routing with fallback chains via OpenRouter
- Observability: Full tracing with Langfuse
- Quality Assurance: Automated evaluation pipeline with LLM-as-judge
- Test-Driven Development: Comprehensive test coverage following TDD principles
graph TD
A[API: POST /posts/generate] --> B[Analyze Topic]
B --> C[Generate Image DALL-E 3]
C --> D1[Generate LinkedIn Post]
C --> D2[Generate Instagram Post]
C --> D3[Generate WordPress Article]
D1 --> E[Wait for Approval]
D2 --> E
D3 --> E
E -->|Approved| F[Finalize & Store]
E -->|Rejected| G[Apply Feedback]
G --> D1
F --> H[Evaluation Pipeline]
H --> I[Store Metrics]
- analyze_topic: Extracts key themes, target audience, and visual concepts
- generate_image: Creates a relevant image using DALL-E 3 via OpenRouter
- generate_linkedin: Professional post (max 3000 chars) with image reference
- generate_instagram: Visual-focused caption with hashtags
- generate_wordpress: Long-form article with embedded image
- wait_for_approval: Human-in-the-loop checkpoint (PostgreSQL-backed)
- apply_feedback: Regenerates content based on human feedback
- finalize: Persists approved content to database
| Component | Technology | Purpose |
|---|---|---|
| Agent Framework | LangGraph | State machine orchestration |
| LLM Provider | OpenRouter | Multi-model routing with fallback |
| Image Generation | DALL-E 3 | Visual content creation |
| API Framework | FastAPI | RESTful API with async support |
| Database | PostgreSQL 16 | State persistence & checkpointing |
| Observability | Langfuse | LLM call tracing & monitoring |
| Testing | Pytest | TDD implementation |
| Containerization | Docker + Compose | Deployment & isolation |
Primary: anthropic/claude-3.5-sonnet
β (on failure)
Fallback 1: openai/gpt-4o
β (on failure)
Fallback 2: openai/gpt-3.5-turbo
Each model attempt includes exponential backoff retry logic.
We use the Repository pattern for clean data access:
PostRepository- Manages post recordsPostContentRepository- Manages platform-specific contentReviewRepository- Tracks human reviewsEvaluationRepository- Stores quality metrics
Type-safe Pydantic models for each platform:
LinkedInPost- Professional posts (max 3000 chars, limited hashtags)InstagramPost- Visual-first (required image, 10-30 hashtags)WordPressPost- Section-based structure with flexible image placement
Pydantic-based state model for the LangGraph workflow:
- Automatic validation
- Type safety throughout the workflow
- Easy serialization for checkpointing
See docs/ARCHITECTURE.md for detailed design decisions.
social-media-post-gen/
βββ src/
β βββ agent/ # LangGraph agent implementation
β β βββ __init__.py
β β βββ state.py # State schema definition
β β βββ nodes.py # Agent node functions
β β βββ graph.py # Graph construction & routing
β βββ api/ # FastAPI application
β β βββ __init__.py
β β βββ main.py # FastAPI app initialization
β β βββ routes.py # API endpoints
β β βββ dependencies.py # Dependency injection
β βββ db/ # Database layer
β β βββ __init__.py
β β βββ models.py # SQLAlchemy models
β β βββ database.py # DB connection & session
β β βββ crud.py # Database operations
β βββ llm/ # LLM integration
β β βββ __init__.py
β β βββ router.py # OpenRouter with fallback
β β βββ observability.py # Langfuse integration
β βββ images/ # Image generation
β β βββ __init__.py
β β βββ generator.py # DALL-E integration
β β βββ storage.py # Image storage logic
β βββ evaluation/ # Quality evaluation
β β βββ __init__.py
β β βββ evaluators.py # Metric calculators
β β βββ runner.py # Evaluation orchestration
β βββ config/ # Configuration
β βββ __init__.py
β βββ settings.py # Pydantic settings
βββ tests/ # Test suite (mirrors src/)
β βββ conftest.py # Pytest fixtures
β βββ test_config.py
β βββ agent/
β βββ api/
β βββ db/
β βββ llm/
β βββ images/
β βββ evaluation/
βββ docs/ # Documentation
β βββ ARCHITECTURE.md # Detailed design docs
β βββ EVALUATION.md # Eval metrics guide
β βββ LEARNINGS.md # Development insights
β βββ TDD_NOTES.md # TDD patterns used
βββ docker/ # Docker configuration
β βββ postgres/ # PostgreSQL init scripts
βββ alembic/ # Database migrations
β βββ versions/
βββ storage/ # Local file storage
β βββ images/ # Generated images
βββ .env.example # Environment template
βββ .gitignore
βββ Dockerfile
βββ docker-compose.yml
βββ pyproject.toml # Dependencies (uv)
βββ README.md # This file
Completed:
- β Project infrastructure and setup
- β All dependencies installed via UV
- β Complete module skeleton (2,644 lines of code)
- β Repository pattern implementation
- β Pydantic schemas for all platforms
- β Architecture documentation
In Progress:
- π§ Alembic database migrations
- π§ Repository unit tests
Next Steps:
- π LLM integration (OpenRouter + Langfuse)
- π Image generation (DALL-E 3)
- π Agent node implementation
- π API endpoint implementation
See TODO.md for detailed progress tracking.
- Python 3.12+
- UV package manager
- Docker & Docker Compose (for deployment)
- OpenRouter API key (get one here) - Required for LLM calls
- (Optional) Langfuse account for observability
Note: The system is currently in development. Basic functionality is not yet implemented.
- Clone and navigate to project:
cd /Users/pedrobruning/Projects/social-media-post-gen- Set up environment variables:
cp .env.example .env
# Edit .env with your API keys- Start services with Docker:
docker-compose up -dThis starts:
- PostgreSQL on port 5432
- FastAPI application on port 8000
- (Optional) Langfuse on port 3000
- Run database migrations:
docker-compose exec app alembic upgrade head- Install dependencies with uv:
uv sync- Start PostgreSQL (using Docker or local install):
docker run -d -p 5432:5432 \
-e POSTGRES_DB=social_media_posts \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=secret \
postgres:16- Run migrations:
uv run alembic upgrade head- Start the API:
uv run uvicorn src.api.main:app --reload --host 0.0.0.0 --port 8000curl -X POST http://localhost:8000/api/posts/generate \
-H "Content-Type: application/json" \
-d '{
"topic": "The future of AI in software development"
}'
# Response:
# {
# "post_id": 1,
# "status": "pending_review",
# "message": "Content generation started"
# }curl http://localhost:8000/api/posts/1
# Response:
# {
# "post_id": 1,
# "topic": "The future of AI in software development",
# "status": "pending_review",
# "image_url": "/api/posts/1/image",
# "linkedin_post": {...},
# "instagram_post": {...},
# "wordpress_post": {...},
# "created_at": "2025-11-16T..."
# }curl -X POST http://localhost:8000/api/posts/1/approvecurl -X POST http://localhost:8000/api/posts/1/reject \
-H "Content-Type: application/json" \
-d '{
"feedback": "Make the LinkedIn post more technical and add code examples"
}'curl -X POST http://localhost:8000/api/posts/1/edit \
-H "Content-Type: application/json" \
-d '{
"platform": "linkedin",
"content": "Updated post content..."
}'curl -X POST http://localhost:8000/api/evaluate/1uv run pytestuv run pytest --cov=src --cov-report=htmluv run pytest tests/agent/test_nodes.py -vThis project follows strict Test-Driven Development:
- Red: Write a failing test that defines desired behavior
- Green: Write minimal code to make the test pass
- Refactor: Improve code quality while keeping tests green
Example from tests/llm/test_router.py:
def test_primary_model_success(mock_openrouter):
"""Test successful call to primary model"""
router = LLMRouter()
response = router.generate("Test prompt")
assert response.content is not None
assert response.model == "anthropic/claude-3.5-sonnet"
assert mock_openrouter.call_count == 1
def test_fallback_on_primary_failure(mock_openrouter):
"""Test fallback to secondary model on primary failure"""
mock_openrouter.side_effect = [Exception("API Error"), "Success"]
router = LLMRouter()
response = router.generate("Test prompt")
assert response.model == "openai/gpt-4o"
assert mock_openrouter.call_count == 2The system automatically evaluates generated content across multiple dimensions:
- Readability Score: Flesch reading ease
- Grammar Check: Language tool validation
- Tone Consistency: Appropriate for each platform
- LinkedIn: Professional tone, character count (β€3000), hashtag appropriateness
- Instagram: Visual focus, hashtag count (10-30), emoji usage
- WordPress: SEO score, structure (headers, paragraphs), readability
- Relevance (1-10): Content matches the original topic
- Engagement (1-10): Likely to generate interactions
- Clarity (1-10): Clear and well-structured
- Approval rate per topic category
- Common rejection reasons
- Time to approval
View evaluation results:
curl http://localhost:8000/api/posts/1/evaluationsAll LLM calls, agent executions, and key events are traced in Langfuse:
- Traces: Full agent execution flow
- Spans: Individual LLM calls with prompts/responses
- Metrics: Token usage, latency, costs per model
- Tags: post_id, platform, model_used, generation_attempt
- Custom Events: human_review, image_generation, feedback_applied
Access your traces at: http://localhost:3000 (if self-hosted) or cloud.langfuse.com
app: FastAPI application with LangGraph agent
- Depends on PostgreSQL
- Exposes port 8000
- Mounts
storage/for images
postgres: PostgreSQL 16 database
- Persists data with volume
- Stores posts, checkpoints, evaluations
langfuse (optional): Self-hosted observability
- Web UI on port 3000
- Requires separate PostgreSQL database
# OpenRouter
OPENROUTER_API_KEY=sk-or-...
# Database
DATABASE_URL=postgresql://admin:secret@postgres:5432/social_media_posts
# Langfuse (cloud or self-hosted)
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://cloud.langfuse.com
# Application
ENVIRONMENT=development
LOG_LEVEL=INFO- Total Lines of Code: ~2,644
- Python Modules: 25 files
- Repositories: 4 classes with 23+ methods
- Pydantic Models: 7 content schemas
- Completion: ~20% (infrastructure complete, implementation in progress)
This project serves as a comprehensive learning resource for:
- Building complex state machines with LangGraph
- Implementing human-in-the-loop patterns
- Managing agent state and checkpoints
- Designing conditional routing logic
- Multi-model routing and fallback strategies
- Cost optimization through model selection
- Retry logic and error handling
- Token usage tracking
- RESTful endpoints for async operations
- Background task processing
- Webhook patterns for notifications
- Error response standardization
- Tracing LLM applications
- Debugging complex agent flows
- Cost and performance monitoring
- Custom event logging
- Writing testable agent code
- Mocking external APIs effectively
- Integration testing strategies
- Achieving high test coverage
- Clean architecture and separation of concerns
- Configuration management
- Database design and migrations
- Containerization and deployment
See TODO.md for detailed task breakdown.
- β Project structure and dependencies
- β Configuration management with Pydantic Settings
- β Repository pattern implementation
- β Platform-specific Pydantic schemas
- β Complete module skeleton (~2,644 lines)
- β Database models (SQLAlchemy)
- β Repository classes (4 repositories)
- β Agent state and schemas
- β LLM router and observability classes
- β API route signatures
- β Evaluation framework
- π§ Alembic migrations
- π Repository unit tests
- π Database integration tests
- π OpenRouter client implementation
- π Fallback chain with retry logic
- π Langfuse tracing integration
- π Cost and token tracking
- π DALL-E 3 integration via OpenRouter
- π Image prompt generation
- π Local storage implementation
- π Topic analysis node
- π Content generation nodes (3 platforms)
- π Human-in-the-loop nodes
- π Graph construction and checkpointing
- π Generate endpoint with background tasks
- π Review endpoints (approve/reject/edit)
- π Evaluation endpoints
- π Image serving
- π Quality evaluators (readability, grammar)
- π Platform-specific evaluators
- π LLM-as-judge implementation
- π Dockerfile (multi-stage build)
- π docker-compose.yml
- π Container orchestration
- π Unit tests (TDD approach)
- π Integration tests
- π >80% code coverage
- β Architecture documentation
- π Evaluation metrics guide
- π Learning journal
- π API examples
- βΈοΈ Web UI for review
- βΈοΈ Multi-language support
- βΈοΈ A/B testing
- βΈοΈ Actual platform publishing
This project uses GitHub Actions for continuous integration and deployment with comprehensive quality checks.
1. CI/CD Pipeline (ci.yml) - Runs on all PRs and pushes to main/develop
Includes 6 parallel jobs:
- Tests: Full test suite with coverage reporting (pytest)
- Linting: Code quality checks (ruff)
- Type Checking: Static type analysis (mypy)
- Format Check: Code formatting validation (black)
- Migrations: Database migration validation (alembic)
- Security Scan: Dependency vulnerability checks (pip-audit)
2. Quick Tests (quick-test.yml) - Fast feedback on feature branches
- Runs tests only (fast mode)
- Quick linting check
- Provides rapid feedback for development
Before pushing, run these commands to ensure CI will pass:
# Run all tests with coverage
uv run pytest tests/ -v --cov=src --cov-report=term-missing
# Check code formatting
uv run black --check src/ tests/
# Run linter
uv run ruff check src/ tests/
# Run type checker
uv run mypy src/
# Validate migrations
uv run alembic checkPro Tip: Run all checks at once:
# Format code
uv run black src/ tests/
# Run tests and quality checks
uv run pytest tests/ -v --cov=src && \
uv run ruff check src/ tests/ && \
uv run mypy src/All pull requests must pass:
- β All tests passing (35 tests)
- β Code formatted with Black
- β No linting errors from Ruff
- β Database migrations valid
Type checking warnings are reported but don't fail CI.
View workflow runs: Actions Tab
This is a learning project, but suggestions and improvements are welcome!
MIT License - feel free to use this for learning and portfolio purposes.
Built with β€οΈ for learning and experimentation