heylead 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- heylead-0.1.0/.gitignore +45 -0
- heylead-0.1.0/LICENSE +21 -0
- heylead-0.1.0/PKG-INFO +105 -0
- heylead-0.1.0/README.md +78 -0
- heylead-0.1.0/pyproject.toml +51 -0
- heylead-0.1.0/src/heylead/__init__.py +3 -0
- heylead-0.1.0/src/heylead/__main__.py +97 -0
- heylead-0.1.0/src/heylead/ai/__init__.py +1 -0
- heylead-0.1.0/src/heylead/ai/icp_generator.py +136 -0
- heylead-0.1.0/src/heylead/ai/llm.py +201 -0
- heylead-0.1.0/src/heylead/ai/message_generator.py +125 -0
- heylead-0.1.0/src/heylead/ai/message_validator.py +205 -0
- heylead-0.1.0/src/heylead/ai/sentiment.py +156 -0
- heylead-0.1.0/src/heylead/ai/voice_analyzer.py +178 -0
- heylead-0.1.0/src/heylead/config.py +175 -0
- heylead-0.1.0/src/heylead/constants.py +125 -0
- heylead-0.1.0/src/heylead/crypto.py +77 -0
- heylead-0.1.0/src/heylead/db/__init__.py +1 -0
- heylead-0.1.0/src/heylead/db/queries.py +393 -0
- heylead-0.1.0/src/heylead/db/schema.py +146 -0
- heylead-0.1.0/src/heylead/formatter.py +145 -0
- heylead-0.1.0/src/heylead/linkedin/__init__.py +35 -0
- heylead-0.1.0/src/heylead/linkedin/backend_client.py +538 -0
- heylead-0.1.0/src/heylead/linkedin/messaging.py +2 -0
- heylead-0.1.0/src/heylead/linkedin/profile.py +2 -0
- heylead-0.1.0/src/heylead/linkedin/rate_limiter.py +124 -0
- heylead-0.1.0/src/heylead/linkedin/search.py +2 -0
- heylead-0.1.0/src/heylead/linkedin/unipile.py +626 -0
- heylead-0.1.0/src/heylead/prompts/voice_analysis.json +6 -0
- heylead-0.1.0/src/heylead/scheduler/__init__.py +1 -0
- heylead-0.1.0/src/heylead/server.py +233 -0
- heylead-0.1.0/src/heylead/tools/__init__.py +1 -0
- heylead-0.1.0/src/heylead/tools/check_replies.py +214 -0
- heylead-0.1.0/src/heylead/tools/create_campaign.py +304 -0
- heylead-0.1.0/src/heylead/tools/generate_send.py +311 -0
- heylead-0.1.0/src/heylead/tools/setup_profile.py +319 -0
- heylead-0.1.0/src/heylead/tools/show_status.py +247 -0
heylead-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.whl
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
*~
|
|
23
|
+
|
|
24
|
+
# OS
|
|
25
|
+
.DS_Store
|
|
26
|
+
Thumbs.db
|
|
27
|
+
|
|
28
|
+
# HeyLead local data (never commit user data)
|
|
29
|
+
.heylead/
|
|
30
|
+
|
|
31
|
+
# Environment / secrets
|
|
32
|
+
.env
|
|
33
|
+
.env.*
|
|
34
|
+
*.enc
|
|
35
|
+
|
|
36
|
+
# Testing
|
|
37
|
+
.pytest_cache/
|
|
38
|
+
.coverage
|
|
39
|
+
htmlcov/
|
|
40
|
+
.mypy_cache/
|
|
41
|
+
.ruff_cache/
|
|
42
|
+
|
|
43
|
+
# Distribution
|
|
44
|
+
*.tar.gz
|
|
45
|
+
*.zip
|
heylead-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HeyLead
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
heylead-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: heylead
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP-native autonomous LinkedIn SDR. Your AI sales rep, one command to fill your pipeline.
|
|
5
|
+
Project-URL: Homepage, https://github.com/D4umak/heylead
|
|
6
|
+
Project-URL: Repository, https://github.com/D4umak/heylead
|
|
7
|
+
Project-URL: Issues, https://github.com/D4umak/heylead/issues
|
|
8
|
+
Author-email: HeyLead <hello@heylead.dev>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,leads,linkedin,mcp,outreach,sales,sdr
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Office/Business
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: click>=8.0.0
|
|
23
|
+
Requires-Dist: cryptography>=41.0.0
|
|
24
|
+
Requires-Dist: httpx>=0.24.0
|
|
25
|
+
Requires-Dist: mcp[cli]>=1.2.0
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# 🎯 HeyLead
|
|
29
|
+
|
|
30
|
+
**Your AI sales rep. One command to fill your pipeline.**
|
|
31
|
+
|
|
32
|
+
HeyLead is an MCP-native autonomous LinkedIn SDR that runs in your terminal. No dashboard. No web app. Just chat.
|
|
33
|
+
|
|
34
|
+
> ⚠️ **Alpha** — Under active development. `setup_profile` is live. Other tools coming soon.
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Install
|
|
40
|
+
pip install heylead
|
|
41
|
+
|
|
42
|
+
# Add to Claude Code
|
|
43
|
+
claude mcp add heylead -- uvx heylead
|
|
44
|
+
|
|
45
|
+
# Then ask Claude:
|
|
46
|
+
# "Set up my LinkedIn profile"
|
|
47
|
+
# "Find me CTOs at fintech startups"
|
|
48
|
+
# "How's my outreach?"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## What It Does
|
|
52
|
+
|
|
53
|
+
HeyLead gives you 5 tools in your AI assistant:
|
|
54
|
+
|
|
55
|
+
| Tool | What it does |
|
|
56
|
+
|------|-------------|
|
|
57
|
+
| `setup_profile` | Analyzes YOUR LinkedIn profile and creates a voice signature — so messages sound like you |
|
|
58
|
+
| `create_campaign` | Takes "find me fintech CTOs" and creates a targeted outreach campaign |
|
|
59
|
+
| `generate_and_send` | Generates personalized invitations and sends them (or queues for your review) |
|
|
60
|
+
| `check_replies` | Checks for new replies, classifies sentiment, surfaces hot leads 🔥 |
|
|
61
|
+
| `show_status` | Your dashboard — stats, acceptance rates, hot leads, account health |
|
|
62
|
+
|
|
63
|
+
## How It Works
|
|
64
|
+
|
|
65
|
+
1. **You describe your target** → "Find me freelance consultants who need scheduling tools"
|
|
66
|
+
2. **HeyLead finds them** → Searches LinkedIn, scores prospects, builds a campaign
|
|
67
|
+
3. **AI writes personalized messages** → Sounds like YOU (voice matching), not a bot
|
|
68
|
+
4. **Copilot mode** → Review first 10 messages, then switch to Autopilot
|
|
69
|
+
5. **You get replies** → HeyLead surfaces hot leads: "🔥 Sarah Chen said: Let's chat!"
|
|
70
|
+
|
|
71
|
+
## Requirements
|
|
72
|
+
|
|
73
|
+
- Python 3.10+
|
|
74
|
+
- Claude Code or Cursor (any MCP-compatible AI assistant)
|
|
75
|
+
- LinkedIn account (free tier works)
|
|
76
|
+
- Gemini API key (free at [aistudio.google.com](https://aistudio.google.com/apikey))
|
|
77
|
+
|
|
78
|
+
## Pricing
|
|
79
|
+
|
|
80
|
+
| Plan | Price | What you get |
|
|
81
|
+
|------|-------|-------------|
|
|
82
|
+
| **Free** | $0 | 50 invitations/mo, 1 campaign, cookie auth |
|
|
83
|
+
| **Pro** | $29/mo | Unlimited, Unipile auth, follow-ups, RAG knowledge base |
|
|
84
|
+
|
|
85
|
+
## Privacy
|
|
86
|
+
|
|
87
|
+
All your data stays on YOUR machine:
|
|
88
|
+
- Contacts → local SQLite
|
|
89
|
+
- Messages → local SQLite
|
|
90
|
+
- LinkedIn cookie → encrypted locally (AES-256)
|
|
91
|
+
- AI processing → goes directly to your LLM provider
|
|
92
|
+
- We receive → nothing
|
|
93
|
+
|
|
94
|
+
## Links
|
|
95
|
+
|
|
96
|
+
- 🌐 [heylead.dev](https://heylead.dev)
|
|
97
|
+
- 📦 [PyPI](https://pypi.org/project/heylead/)
|
|
98
|
+
- 🐛 [Issues](https://github.com/heylead-ai/mcp-server/issues)
|
|
99
|
+
- 💬 Discord (coming soon)
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT (code) — see [LICENSE](LICENSE)
|
|
104
|
+
|
|
105
|
+
Knowledge base and prompt configurations are proprietary.
|
heylead-0.1.0/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 🎯 HeyLead
|
|
2
|
+
|
|
3
|
+
**Your AI sales rep. One command to fill your pipeline.**
|
|
4
|
+
|
|
5
|
+
HeyLead is an MCP-native autonomous LinkedIn SDR that runs in your terminal. No dashboard. No web app. Just chat.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Alpha** — Under active development. `setup_profile` is live. Other tools coming soon.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install
|
|
13
|
+
pip install heylead
|
|
14
|
+
|
|
15
|
+
# Add to Claude Code
|
|
16
|
+
claude mcp add heylead -- uvx heylead
|
|
17
|
+
|
|
18
|
+
# Then ask Claude:
|
|
19
|
+
# "Set up my LinkedIn profile"
|
|
20
|
+
# "Find me CTOs at fintech startups"
|
|
21
|
+
# "How's my outreach?"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## What It Does
|
|
25
|
+
|
|
26
|
+
HeyLead gives you 5 tools in your AI assistant:
|
|
27
|
+
|
|
28
|
+
| Tool | What it does |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| `setup_profile` | Analyzes YOUR LinkedIn profile and creates a voice signature — so messages sound like you |
|
|
31
|
+
| `create_campaign` | Takes "find me fintech CTOs" and creates a targeted outreach campaign |
|
|
32
|
+
| `generate_and_send` | Generates personalized invitations and sends them (or queues for your review) |
|
|
33
|
+
| `check_replies` | Checks for new replies, classifies sentiment, surfaces hot leads 🔥 |
|
|
34
|
+
| `show_status` | Your dashboard — stats, acceptance rates, hot leads, account health |
|
|
35
|
+
|
|
36
|
+
## How It Works
|
|
37
|
+
|
|
38
|
+
1. **You describe your target** → "Find me freelance consultants who need scheduling tools"
|
|
39
|
+
2. **HeyLead finds them** → Searches LinkedIn, scores prospects, builds a campaign
|
|
40
|
+
3. **AI writes personalized messages** → Sounds like YOU (voice matching), not a bot
|
|
41
|
+
4. **Copilot mode** → Review first 10 messages, then switch to Autopilot
|
|
42
|
+
5. **You get replies** → HeyLead surfaces hot leads: "🔥 Sarah Chen said: Let's chat!"
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Python 3.10+
|
|
47
|
+
- Claude Code or Cursor (any MCP-compatible AI assistant)
|
|
48
|
+
- LinkedIn account (free tier works)
|
|
49
|
+
- Gemini API key (free at [aistudio.google.com](https://aistudio.google.com/apikey))
|
|
50
|
+
|
|
51
|
+
## Pricing
|
|
52
|
+
|
|
53
|
+
| Plan | Price | What you get |
|
|
54
|
+
|------|-------|-------------|
|
|
55
|
+
| **Free** | $0 | 50 invitations/mo, 1 campaign, cookie auth |
|
|
56
|
+
| **Pro** | $29/mo | Unlimited, Unipile auth, follow-ups, RAG knowledge base |
|
|
57
|
+
|
|
58
|
+
## Privacy
|
|
59
|
+
|
|
60
|
+
All your data stays on YOUR machine:
|
|
61
|
+
- Contacts → local SQLite
|
|
62
|
+
- Messages → local SQLite
|
|
63
|
+
- LinkedIn cookie → encrypted locally (AES-256)
|
|
64
|
+
- AI processing → goes directly to your LLM provider
|
|
65
|
+
- We receive → nothing
|
|
66
|
+
|
|
67
|
+
## Links
|
|
68
|
+
|
|
69
|
+
- 🌐 [heylead.dev](https://heylead.dev)
|
|
70
|
+
- 📦 [PyPI](https://pypi.org/project/heylead/)
|
|
71
|
+
- 🐛 [Issues](https://github.com/heylead-ai/mcp-server/issues)
|
|
72
|
+
- 💬 Discord (coming soon)
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT (code) — see [LICENSE](LICENSE)
|
|
77
|
+
|
|
78
|
+
Knowledge base and prompt configurations are proprietary.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "heylead"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MCP-native autonomous LinkedIn SDR. Your AI sales rep, one command to fill your pipeline."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "HeyLead", email = "hello@heylead.dev" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["mcp", "linkedin", "outreach", "sdr", "leads", "sales", "ai"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Office/Business",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"mcp[cli]>=1.2.0",
|
|
29
|
+
"httpx>=0.24.0",
|
|
30
|
+
"cryptography>=41.0.0",
|
|
31
|
+
"click>=8.0.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
heylead = "heylead.server:main"
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/D4umak/heylead"
|
|
39
|
+
Repository = "https://github.com/D4umak/heylead"
|
|
40
|
+
Issues = "https://github.com/D4umak/heylead/issues"
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/heylead"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff]
|
|
46
|
+
target-version = "py310"
|
|
47
|
+
line-length = 100
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
|
51
|
+
asyncio_mode = "auto"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""HeyLead CLI entry point.
|
|
2
|
+
|
|
3
|
+
This module allows running HeyLead as:
|
|
4
|
+
python -m heylead # Start MCP server
|
|
5
|
+
python -m heylead init # First-time setup
|
|
6
|
+
python -m heylead version # Show version
|
|
7
|
+
python -m heylead reset # Delete all data
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main() -> None:
|
|
16
|
+
"""CLI router — simple arg parsing without pulling in click for MCP mode."""
|
|
17
|
+
args = sys.argv[1:]
|
|
18
|
+
|
|
19
|
+
if not args:
|
|
20
|
+
# Default: start MCP server
|
|
21
|
+
from .server import main as serve
|
|
22
|
+
serve()
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
cmd = args[0].lower()
|
|
26
|
+
|
|
27
|
+
if cmd == "version" or cmd == "--version" or cmd == "-v":
|
|
28
|
+
from . import __version__
|
|
29
|
+
print(f"HeyLead v{__version__}")
|
|
30
|
+
|
|
31
|
+
elif cmd == "init":
|
|
32
|
+
from . import config
|
|
33
|
+
config.ensure_dirs()
|
|
34
|
+
cfg = config.load_config()
|
|
35
|
+
print("✅ HeyLead initialized!")
|
|
36
|
+
print(f" Config: {config.config_path()}")
|
|
37
|
+
print(f" Database: {config.db_path()}")
|
|
38
|
+
print(f" Logs: {config.log_path()}")
|
|
39
|
+
print()
|
|
40
|
+
print("Next steps:")
|
|
41
|
+
print("1. Add your credentials to ~/.heylead/config.json:")
|
|
42
|
+
print(' "unipile_api_url": "https://apiXX.unipile.com:XXXXX"')
|
|
43
|
+
print(' "unipile_api_key": "YOUR_UNIPILE_API_KEY"')
|
|
44
|
+
print(' "api_keys": { "gemini": "YOUR_GEMINI_KEY" }')
|
|
45
|
+
print(" (Get a free Gemini key at: https://aistudio.google.com/apikey)")
|
|
46
|
+
print("2. Add HeyLead to Claude Code:")
|
|
47
|
+
print(" claude mcp add heylead -- python -m heylead")
|
|
48
|
+
print("3. Then ask Claude: 'Set up my LinkedIn profile'")
|
|
49
|
+
|
|
50
|
+
elif cmd == "reset":
|
|
51
|
+
confirm = input("⚠️ This will delete ALL HeyLead data. Continue? (yes/no): ")
|
|
52
|
+
if confirm.strip().lower() == "yes":
|
|
53
|
+
from . import config
|
|
54
|
+
from .db.schema import reset_db
|
|
55
|
+
import shutil
|
|
56
|
+
|
|
57
|
+
reset_db()
|
|
58
|
+
|
|
59
|
+
# Remove legacy cookie file if it exists
|
|
60
|
+
cookie_path = config.cookie_path()
|
|
61
|
+
if cookie_path.exists():
|
|
62
|
+
cookie_path.unlink()
|
|
63
|
+
|
|
64
|
+
# Remove config
|
|
65
|
+
cfg_path = config.config_path()
|
|
66
|
+
if cfg_path.exists():
|
|
67
|
+
cfg_path.unlink()
|
|
68
|
+
|
|
69
|
+
# Remove logs
|
|
70
|
+
log_dir = config._heylead_home() / "logs"
|
|
71
|
+
if log_dir.exists():
|
|
72
|
+
shutil.rmtree(log_dir)
|
|
73
|
+
|
|
74
|
+
print("✅ All HeyLead data deleted.")
|
|
75
|
+
else:
|
|
76
|
+
print("Cancelled.")
|
|
77
|
+
|
|
78
|
+
elif cmd == "help" or cmd == "--help" or cmd == "-h":
|
|
79
|
+
print("HeyLead — MCP-native autonomous LinkedIn SDR")
|
|
80
|
+
print()
|
|
81
|
+
print("Usage:")
|
|
82
|
+
print(" heylead Start the MCP server (stdio transport)")
|
|
83
|
+
print(" heylead init Initialize HeyLead (create config + dirs)")
|
|
84
|
+
print(" heylead version Show version")
|
|
85
|
+
print(" heylead reset Delete all data")
|
|
86
|
+
print()
|
|
87
|
+
print("Add to Claude Code:")
|
|
88
|
+
print(" claude mcp add heylead -- python -m heylead")
|
|
89
|
+
|
|
90
|
+
else:
|
|
91
|
+
print(f"Unknown command: {cmd}")
|
|
92
|
+
print("Run 'heylead help' for usage.")
|
|
93
|
+
sys.exit(1)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""HeyLead AI layer — LLM clients, voice analysis, message generation."""
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""ICP (Ideal Customer Profile) generator.
|
|
2
|
+
|
|
3
|
+
Takes a natural language target description like "fintech CTOs" and
|
|
4
|
+
generates a structured ICP with LinkedIn search parameters.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from .llm import LLMClient
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
ICP_SYSTEM = """You are an expert B2B sales strategist. You convert natural language descriptions of target customers into structured Ideal Customer Profiles (ICPs) with LinkedIn search parameters.
|
|
18
|
+
|
|
19
|
+
You are precise and output structured JSON only."""
|
|
20
|
+
|
|
21
|
+
ICP_PROMPT = """Convert this target description into a structured ICP with LinkedIn search parameters.
|
|
22
|
+
|
|
23
|
+
## TARGET DESCRIPTION
|
|
24
|
+
"{target_description}"
|
|
25
|
+
|
|
26
|
+
## USER CONTEXT (their profile)
|
|
27
|
+
Name: {user_name}
|
|
28
|
+
Title: {user_title}
|
|
29
|
+
Company: {user_company}
|
|
30
|
+
Expertise: {user_expertise}
|
|
31
|
+
|
|
32
|
+
## TASK
|
|
33
|
+
Generate a structured ICP that can be used to search LinkedIn. Include:
|
|
34
|
+
|
|
35
|
+
1. **ICP Summary**: One-line description of the ideal customer
|
|
36
|
+
2. **Search Parameters**: LinkedIn search filters
|
|
37
|
+
3. **Segments**: 1-3 target segments (from most to least specific)
|
|
38
|
+
4. **Relevance Hook**: Why the user (above) would be credible reaching out to this audience
|
|
39
|
+
5. **Campaign Name**: Auto-generate a short campaign name if not provided
|
|
40
|
+
|
|
41
|
+
Each segment should have:
|
|
42
|
+
- `keywords`: LinkedIn search keywords (comma-separated)
|
|
43
|
+
- `titles`: Job titles to target (list)
|
|
44
|
+
- `seniority`: Seniority levels (list from: owner, partner, cxo, vp, director, manager, senior, entry)
|
|
45
|
+
- `industries`: LinkedIn industries (list)
|
|
46
|
+
- `company_size`: Company sizes (list from: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+)
|
|
47
|
+
- `geography`: Regions/countries (list, or empty for global)
|
|
48
|
+
- `estimated_results`: Rough estimate of how many LinkedIn results this would yield
|
|
49
|
+
|
|
50
|
+
## RESPONSE FORMAT
|
|
51
|
+
Return ONLY valid JSON (no markdown, no explanation):
|
|
52
|
+
{{
|
|
53
|
+
"summary": "...",
|
|
54
|
+
"campaign_name": "...",
|
|
55
|
+
"relevance_hook": "...",
|
|
56
|
+
"segments": [
|
|
57
|
+
{{
|
|
58
|
+
"name": "Primary",
|
|
59
|
+
"keywords": "...",
|
|
60
|
+
"titles": ["CTO", "VP Engineering"],
|
|
61
|
+
"seniority": ["cxo", "vp", "director"],
|
|
62
|
+
"industries": ["Financial Services", "Fintech"],
|
|
63
|
+
"company_size": ["11-50", "51-200"],
|
|
64
|
+
"geography": [],
|
|
65
|
+
"estimated_results": "200-500"
|
|
66
|
+
}}
|
|
67
|
+
]
|
|
68
|
+
}}"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def generate_icp(
|
|
72
|
+
target_description: str,
|
|
73
|
+
user_profile: dict[str, Any] | None = None,
|
|
74
|
+
) -> dict[str, Any]:
|
|
75
|
+
"""Generate an ICP from a natural language target description.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
target_description: e.g., "CTOs at fintech startups", "yoga studio owners in California"
|
|
79
|
+
user_profile: The user's own profile data (for relevance hook)
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Structured ICP dict with search parameters.
|
|
83
|
+
"""
|
|
84
|
+
user_name = ""
|
|
85
|
+
user_title = ""
|
|
86
|
+
user_company = ""
|
|
87
|
+
user_expertise = ""
|
|
88
|
+
|
|
89
|
+
if user_profile:
|
|
90
|
+
user_name = user_profile.get("name", "")
|
|
91
|
+
user_title = user_profile.get("title", "")
|
|
92
|
+
user_company = user_profile.get("company", "")
|
|
93
|
+
user_expertise = user_profile.get("core", user_profile.get("headline", ""))
|
|
94
|
+
|
|
95
|
+
prompt = ICP_PROMPT.format(
|
|
96
|
+
target_description=target_description,
|
|
97
|
+
user_name=user_name or "Unknown",
|
|
98
|
+
user_title=user_title or "Founder",
|
|
99
|
+
user_company=user_company or "Unknown",
|
|
100
|
+
user_expertise=user_expertise or "Not specified",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
client = LLMClient()
|
|
104
|
+
raw = await client.generate(prompt, system=ICP_SYSTEM, temperature=0.4)
|
|
105
|
+
|
|
106
|
+
# Parse JSON
|
|
107
|
+
cleaned = raw.strip()
|
|
108
|
+
if cleaned.startswith("```"):
|
|
109
|
+
lines = cleaned.split("\n")
|
|
110
|
+
cleaned = "\n".join(
|
|
111
|
+
line for line in lines if not line.strip().startswith("```")
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
result = json.loads(cleaned)
|
|
116
|
+
except json.JSONDecodeError:
|
|
117
|
+
logger.warning("Failed to parse ICP JSON, building minimal structure")
|
|
118
|
+
result = {
|
|
119
|
+
"summary": f"Target: {target_description}",
|
|
120
|
+
"campaign_name": target_description[:30],
|
|
121
|
+
"relevance_hook": "",
|
|
122
|
+
"segments": [
|
|
123
|
+
{
|
|
124
|
+
"name": "Primary",
|
|
125
|
+
"keywords": target_description,
|
|
126
|
+
"titles": [],
|
|
127
|
+
"seniority": [],
|
|
128
|
+
"industries": [],
|
|
129
|
+
"company_size": [],
|
|
130
|
+
"geography": [],
|
|
131
|
+
"estimated_results": "Unknown",
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result
|