Analiza el estilo de comunicación de LinkedIn y genera publicaciones auténticas con IA
PersonaPost scrapes a LinkedIn user's public posts, uses Google Gemini 1.5 Pro to build a detailed personality profile, and then generates 20 LinkedIn posts on any topic — written exactly as that person would write them.
| Layer | Technology |
|---|---|
| Frontend | React 18 + Vite + TailwindCSS + Zustand |
| Backend | Python 3.11 + Flask 3 + SQLAlchemy |
| Database | SQLite (embedded) |
| AI | Google Gemini 1.5 Pro API |
| Scraping | Playwright (headless Chromium) |
- Python 3.10+
- Node.js 18+
- Google Gemini API Key — Get one here
cd personapost/backend
# Create virtual environment
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS/Linux
# Install dependencies
pip install -r requirements.txt
# Install Playwright browser
playwright install chromium
# Copy environment template
copy .env.example .envEdit .env and fill in your values:
GEMINI_API_KEY=your_actual_gemini_api_key
FLASK_SECRET_KEY=any_random_string_hereStart the Flask server:
python app.py
# Server runs on http://localhost:5000cd personapost/frontend
# Install dependencies
npm install
# Start dev server
npm run dev
# App runs on http://localhost:5173- Go to Analizar page
- Paste a LinkedIn URL (e.g.
https://www.linkedin.com/in/midudev/) - Click Analizar Perfil — watch the progress steps
- View the Personality Card with tone, technical level, emoji usage, key phrases
Scraping tip: LinkedIn requires authentication for many profiles. If scraping fails, use the "Pegar publicaciones manualmente" option and paste the raw post texts separated by
---.
- Go to Generar page
- Select an analyzed profile from the dropdown
- Enter a topic (e.g. "IA en desarrollo web", "manga y anime")
- Click Generar 20 Publicaciones
- Wait 30–60 seconds while Gemini generates your posts
- Copy individual posts or browse all in the grid
- View all analyzed profiles in Historial
- Browse past batches and individual posts
- Delete profiles or specific posts
| Variable | Required | Description |
|---|---|---|
GEMINI_API_KEY |
✅ | Your Google Gemini API key |
FLASK_SECRET_KEY |
✅ | Random secret for Flask sessions |
DATABASE_URL |
❌ | SQLite path (default: sqlite:///personapost.db) |
LINKEDIN_EMAIL |
❌ | LinkedIn email for authenticated scraping |
LINKEDIN_PASSWORD |
❌ | LinkedIn password for authenticated scraping |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/analyze-profile |
Scrape + analyze a LinkedIn profile |
GET |
/api/profiles |
List all analyzed profiles |
GET |
/api/profiles/<id> |
Get profile with full analysis |
DELETE |
/api/profiles/<id> |
Delete profile + all data |
POST |
/api/generate-posts |
Generate 20 posts for a topic |
GET |
/api/batches/<profile_id> |
Get all batches for a profile |
GET |
/api/posts/<batch_id> |
Get all posts in a batch |
DELETE |
/api/posts/<id> |
Delete a single post |
PATCH |
/api/posts/<id>/copy |
Increment copy counter |
personapost/
├── backend/
│ ├── app.py Flask application factory
│ ├── config.py Configuration from .env
│ ├── models.py SQLAlchemy ORM models
│ ├── routes/
│ │ ├── profiles.py Profile analysis endpoints
│ │ └── posts.py Post generation endpoints
│ ├── services/
│ │ ├── scraper.py LinkedIn Playwright scraper
│ │ ├── gemini.py Gemini API integration
│ │ └── analyzer.py Analysis orchestrator
│ ├── requirements.txt
│ └── .env.example
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── Layout/ Navbar, Layout wrapper
│ │ │ ├── Analyzer/ ScrapeProgress, PersonalityCard
│ │ │ ├── Generator/ PostCard, PostGrid
│ │ │ └── History/ ProfileList
│ │ ├── pages/
│ │ │ ├── Home.jsx Landing page
│ │ │ ├── Analyze.jsx LinkedIn URL + analysis flow
│ │ │ ├── Generate.jsx Post generation
│ │ │ ├── Posts.jsx View generated posts
│ │ │ └── History.jsx Past profiles + batches
│ │ ├── hooks/
│ │ │ ├── useProfileAnalysis.js
│ │ │ └── usePostGenerator.js
│ │ ├── services/api.js All axios calls
│ │ └── store/appStore.js Zustand global state
│ ├── package.json
│ └── vite.config.js
└── README.md
LinkedIn actively blocks scraping. Here's what PersonaPost does to mitigate:
- ✅ Randomized delays (2–5 seconds between actions)
- ✅ Realistic User-Agent rotation
- ✅ Automation flag masking (
navigator.webdriver = undefined) - ✅ Optional authenticated scraping with your credentials
- ✅ Manual paste fallback — if scraping fails, simply paste post texts
If scraping consistently fails, use the manual paste mode — it works identically for the AI analysis.