PersonaAI enables marketers and product teams to instantly test campaign variants (A vs B) against diverse persona profiles using AI evaluation, providing actionable insights before launching campaigns.
- Loads personas from your Supabase database (100k+ rich persona profiles)
- Evaluates campaigns using Google's Gemini API as an expert marketing psychologist
- Generates comprehensive reports with winner determination, demographic insights, and recommendations
- Python 3.11+
- Supabase account with persona data
- Google Gemini API key
# Clone the repository
git clone https://github.com/yourusername/personaAI.git
cd personaAI
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Set up environment variables
cp env.example .env
# Edit .env with your actual credentialsEdit .env file with your credentials:
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your_supabase_key
GEMINI_API_KEY=your_gemini_api_key
GEMINI_MODEL=gemini-1.5-flashpython run_simulation.py \
--personas random \
--count 50 \
--campaign_a "Unlock Your Potential with Our Premium Course" \
--campaign_b "Transform Your Career in 30 Days" \
--output reports/my_test.json \
--format bothpython run_simulation.py \
--personas "uuid1,uuid2,uuid3" \
--campaign_a "Your Campaign A Text" \
--campaign_b "Your Campaign B Text" \
--output reports/specific_test.json| Argument | Description | Required | Default |
|---|---|---|---|
--personas |
Comma-separated UUIDs or "random" | Yes | - |
--count |
Number of random personas | No | 10 |
--campaign_a |
Campaign A text | Yes | - |
--campaign_b |
Campaign B text | Yes | - |
--output |
Output file path | No | reports/simulation_report.json |
--format |
Output format: json, markdown, or both | No | both |
--max-concurrent |
Max concurrent API calls | No | 10 |
{
"simulation_metadata": {
"timestamp": "2025-10-26T10:30:00",
"total_personas_evaluated": 50,
"campaign_a": "...",
"campaign_b": "..."
},
"winner": {
"winning_campaign": "B",
"margin": "60% vs 40%",
"confidence": 0.85
},
"aggregate_statistics": {
"campaign_a_preference_count": 20,
"campaign_b_preference_count": 30,
"average_scores": {
"campaign_a": {"relevance": 75, "trust": 80, "appeal": 70},
"campaign_b": {"relevance": 85, "trust": 82, "appeal": 88}
}
},
"key_insights": [...],
"recommendations": "Campaign B is the clear winner...",
"persona_details": [...]
}The Markdown report includes:
- Winner announcement with confidence level
- Side-by-side campaign comparison
- Aggregate statistics table
- Key insights with impact ratings
- Actionable recommendations
- Detailed persona-by-persona breakdown
personaAI/
βββ src/
β βββ config.py # Configuration management
β βββ persona_loader.py # Load personas from Supabase
β βββ gemini_evaluator.py # Gemini API integration
β βββ report_generator.py # Report generation
βββ tests/
β βββ test_persona_loader.py
β βββ test_gemini_evaluator.py
β βββ test_report_generator.py
β βββ fixtures/
β βββ sample_personas.json
βββ reports/ # Generated reports go here
βββ run_simulation.py # Main entry point
βββ requirements.txt
βββ README.md
# Run all tests
pytest
# Run specific test file
pytest tests/test_gemini_evaluator.py
# Run with coverage
pytest --cov=src tests/
# Run with verbose output
pytest -vYou can also use PersonaAI as a library:
import asyncio
from src.config import Config
from src.persona_loader import PersonaLoader
from src.gemini_evaluator import GeminiEvaluator
from src.report_generator import ReportGenerator
# Validate config
Config.validate()
# Load personas
loader = PersonaLoader(Config.SUPABASE_URL, Config.SUPABASE_KEY)
personas = loader.load_random_personas(count=50)
# Evaluate
evaluator = GeminiEvaluator(Config.GEMINI_API_KEY)
results = asyncio.run(evaluator.evaluate_batch(
personas,
campaign_a="Your Campaign A",
campaign_b="Your Campaign B"
))
# Generate report
reporter = ReportGenerator()
report = reporter.generate_report(results, "Campaign A", "Campaign B")
reporter.save_report(report, "reports/my_report.json", format="json")
reporter.save_report(report, "reports/my_report.md", format="markdown")-
Persona Loading: Fetches persona profiles from Supabase with rich attributes:
- Demographics (age, education, occupation)
- 6 persona narratives (professional, sports, arts, travel, culinary, general)
- Skills, interests, and career goals
-
AI Evaluation: For each persona, Gemini API:
- Analyzes both campaigns through the persona's perspective
- Scores on relevance, trust, and appeal (0-100)
- Provides detailed reasoning grounded in persona attributes
- Returns structured JSON with preference and confidence
-
Aggregation & Insights:
- Calculates winning campaign based on preference count
- Computes average scores across all personas
- Generates demographic breakdowns
- Produces actionable recommendations
Each campaign is scored on:
- Relevance (0-100): Alignment with persona's interests, profession, and life context
- Trust (0-100): Credibility based on persona's education and values
- Appeal (0-100): Emotional resonance with lifestyle and aspirations
gemini-1.5-flash(default): Faster, cost-effectivegemini-1.5-pro: Higher quality, more detailed reasoning
Adjust MAX_CONCURRENT_EVALUATIONS in .env to control:
- Higher = faster but more API load
- Lower = slower but more stable
- Default: 10 (good balance)
Ensure your .env file exists and contains all required variables:
cp env.example .env
# Edit .env with your actual credentialsCheck your Supabase credentials and ensure:
- Table name is
personas - You have data in the table
- API key has read permissions
- Check API key validity
- Verify you have quota remaining
- Check if gemini-1.5-flash is available in your region
The system automatically handles malformed responses with fallback results. Check logs for details.
- 10 personas: ~10 seconds
- 50 personas: ~30 seconds
- 100 personas: ~60 seconds
(Times vary based on Gemini API latency and concurrency settings)
- Never commit your
.envfile - Use service role keys sparingly (prefer anon key with RLS)
- Rotate API keys regularly
- Consider rate limiting for production use
python run_simulation.py \
--personas random --count 100 \
--campaign_a "π― Boost Your Sales by 50% This Quarter" \
--campaign_b "Simple Strategies for Doubling Revenue" \
--output reports/email_subject_test.jsonpython run_simulation.py \
--personas random --count 75 \
--campaign_a "The #1 Tool for Modern Marketers" \
--campaign_b "Marketing Made Simple and Effective" \
--output reports/headline_test.jsonpython run_simulation.py \
--personas random --count 50 \
--campaign_a "Join 10,000+ Happy Customers" \
--campaign_b "Start Your Free Trial Today - No Credit Card Required" \
--output reports/ad_copy_test.jsonContributions welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Submit a pull request
MIT License - see LICENSE file for details
For issues, questions, or suggestions:
- Open an issue on GitHub
- Check existing issues for solutions
- Review the troubleshooting section above
- REST API wrapper for frontend integration
- Multi-variant testing (A/B/C/D/E)
- Historical trend analysis
- Custom persona creation
- Visualization dashboard
- Integration with actual A/B testing platforms
Built with β€οΈ using Google Gemini API and Supabase