A comprehensive web-based tool that gathers poker-room data from Bravo Poker Live and Poker Atlas, enriches it with decision-maker information, and generates personalized first-line outreach copy using AI.
- Automated Data Collection: Scrape venue data from Bravo Poker Live and Poker Atlas using Playwright
- Data Normalization: Intelligent deduplication and schema normalization across platforms
- Decision-Maker Enrichment: Integration with Apollo.io for contact information
- AI Personalization: Generate personalized outreach copy using OpenAI GPT
- One-Click Workflow: Single button to refresh all data and generate copy
- Modern Dashboard: Clean React interface with real-time updates
- CSV Export: Export all data with generated copy for outreach campaigns
- Frontend: Next.js 14 with React, TypeScript, Tailwind CSS
- Backend: FastAPI with Python 3.11
- Database: PostgreSQL 15 with SQLAlchemy ORM
- Scraping: Playwright (headless Chrome)
- AI: OpenAI API (GPT-3.5-turbo)
- Enrichment: Apollo.io API
- Deployment: Docker & Docker Compose
- Docker & Docker Compose
- OpenAI API key
- Apollo.io API key (for decision-maker enrichment)
-
Clone the repository
git clone <repository-url> cd AI-personalization-system
-
Set up environment variables
cp .env.example .env # Edit .env with your API keys -
Run with Docker Compose
docker-compose -f docker-compose.dev.yml up -d
-
Access the application
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- API Documentation: http://localhost:8000/docs
├── backend/ # FastAPI application
│ ├── main.py # Main API server
│ ├── database.py # Database models and connection
│ ├── data_normalizer.py # Data normalization logic
│ ├── enrichment_service.py # Apollo.io integration
│ ├── ai_personalization.py # OpenAI integration
│ └── requirements.txt # Python dependencies
├── frontend/ # Next.js application
│ ├── app/ # App router pages
│ ├── package.json # Node.js dependencies
│ └── Dockerfile # Frontend container
├── scrapers/ # Data collection scripts
│ ├── base_scraper.py # Base scraper class
│ ├── bravo_scraper.py # Bravo Poker Live scraper
│ └── poker_atlas_scraper.py # Poker Atlas scraper
├── database/ # Database schema
│ └── init.sql # PostgreSQL initialization
├── docker-compose.yml # Production configuration
├── docker-compose.dev.yml # Development configuration
└── README.md # This file
Copy .env.example to .env and configure:
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/poker_outreach
# OpenAI API (required for AI copy generation)
OPENAI_API_KEY=your_openai_api_key_here
# Apollo.io API (required for decision-maker enrichment)
APOLLO_API_KEY=your_apollo_api_key_here
# Backend API
API_HOST=0.0.0.0
API_PORT=8000
# Frontend
NEXT_PUBLIC_API_URL=http://localhost:8000
NEXT_PUBLIC_APP_URL=http://localhost:3000POST /api/refresh- Trigger data refresh and enrichmentGET /api/venues- Get all venues (paginated)GET /api/venues/{id}- Get specific venue detailsGET /api/venues/{id}/games- Get games for a venueGET /api/venues/{id}/promotions- Get promotions for a venueGET /api/venues/{id}/decision-makers- Get decision makers for a venueGET /api/venues/{id}/copy- Get AI-generated copy for a venuePOST /api/venues/{id}/regenerate-copy- Regenerate AI copy for a venue
GET /api/export/csv- Export all data as CSV
GET /api/stats- Get database statistics
GET /docs- Interactive API documentation (Swagger)GET /redoc- Alternative API documentation
The application uses PostgreSQL with the following main tables:
- venues: Poker venue information (name, location, contact details)
- games: Game types, stakes, buy-ins, table counts
- promotions: Venue promotions and bonuses
- decision_makers: Contact information for key personnel
- ai_generated_copy: Personalized outreach copy with context
- data_source_metadata: Tracking of scraping operations
-
Set up PostgreSQL
# Create database createdb poker_outreach # Run initialization script psql -d poker_outreach -f database/init.sql
-
Install backend dependencies
cd backend pip install -r requirements.txt playwright install chromium -
Install frontend dependencies
cd frontend npm install -
Run services
# Terminal 1 - Backend cd backend uvicorn main:app --reload --host 0.0.0.0 --port 8000 # Terminal 2 - Frontend cd frontend npm run dev
- Create a new scraper class inheriting from
BaseScraper - Implement
scrape_venues()andscrape_venue_details()methods - Add the scraper to the main refresh process in
main.py
Edit the _build_prompt() method in ai_personalization.py to customize the outreach copy generation.
- No LinkedIn Scraping: We do not automate or scrape LinkedIn data
- Rate Limiting: All external requests are rate-limited
- Public Data Only: Only publicly accessible information is collected
- robots.txt: Scrapers respect robots.txt files
- API Terms: All third-party API usage follows terms of service
-
Click "Refresh Data" - The system automatically:
- Scrapes venues from Bravo Poker Live and Poker Atlas
- Normalizes and deduplicates the data
- Enriches venues with decision-maker information
- Generates personalized outreach copy
-
Review Results - Browse venues, games, promotions, and contacts
-
Export Data - Download CSV with all information and generated copy
-
Copy & Paste - Use the generated first-line copy for outreach
- API Keys Required: Both OpenAI and Apollo.io API keys are needed for full functionality
- Rate Limits: Free API tiers have usage limits
- Data Accuracy: Scraped data may vary in quality and completeness
- Background Processing: Data refresh runs in the background and may take several minutes
- Scraping Fails: Check if target websites have changed their structure
- API Errors: Verify API keys are valid and have sufficient credits
- Database Connection: Ensure PostgreSQL is running and accessible
- Docker Issues: Check logs with
docker-compose logs
Enable debug logging by setting the environment variable:
export LOG_LEVEL=DEBUG- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
For issues and questions:
- Check the troubleshooting section
- Review API documentation at
/docs - Check logs for error messages
- Create an issue with detailed information
Built with ❤️ for the poker community