Pre-call due-diligence intelligence for sales reps — action tips + fact dossiers from one research pass.
Project description
🟡 SalesBuff — Backend (FastAPI)
The Python service that turns a sales rep's prompt into a citation-grounded Actions brief and a Facts dossier. Built with FastAPI + asyncio.
Architecture deep-dive (folders, data flow, prompts): see
ARCHITECTURE.md.
What it does
One request runs a 3-stage pipeline:
- Resolve — figure out the real buyer, contact, seller, meeting motion (expansion vs displacement), and any competitor to beat. (LLM → Tavily search → LLM)
- Research — deep-research each entity on the web; optionally search court records. (Tavily Deep Research + CourtListener)
- Brief — from one shared fact pack, generate Actions (coaching moves) and Facts (evidence dossier) concurrently, then ground every card to a real source URL. (OpenAI)
Because a full run takes ~1–2 minutes, the API is job-based: submit, then poll.
Two ways to use it
It's one package with feature extras you mix and match:
| Install | You get |
|---|---|
pip install salesbuff |
Shared core — enough to call the SDK from your code. |
pip install "salesbuff[precall]" |
The pre-call due-diligence feature (this product). |
pip install "salesbuff[onfly]" |
Live on-the-fly insights (planned). |
pip install "salesbuff[api]" |
The FastAPI host layer + the salesbuff-serve command. |
pip install "salesbuff[precall,api]" |
Pre-call and host it as an API. |
pip install "salesbuff[all]" |
Everything. |
Extras are additive — they layer optional dependencies onto the core. One
pip installpulls the package and all the deps for the extras you pick; there's no separate requirements step.
Host it from the terminal (no code)
pip install "salesbuff[api]"
# set OPENAI_API_KEY + TAVILY_API_KEY in your env (or a .env), then:
salesbuff-serve --port 8000 # defaults to $PORT or 8000
As a library (SDK)
from salesbuff import SalesBuff
async with SalesBuff(openai_api_key="sk-...", tavily_api_key="tvly-...") as sb:
result = await sb.research("Meeting the VP of Ops at Acme Health next week...")
print(result.brief) # Actions brief (or None)
print(result.facts) # Facts dossier (or None)
One-shot synchronous helper (for scripts/notebooks):
from salesbuff import research_once
result = research_once(
"Expanding our rollout at Acme Health...",
openai_api_key="sk-...",
tavily_api_key="tvly-...",
)
courtlistener_token=... is optional (enables court-record lookups). Advanced
tuning (research_concurrency, openai_model, …) can be passed as keyword args.
The FastAPI service is just a thin host over this same SDK — both share one engine, so they never drift.
Setup (local)
Run everything from the SalesBuff/ directory (the parent of the salesbuff
package).
cd SalesBuff
pip install -r salesbuff/requirements.txt
cp salesbuff/.env.example salesbuff/.env # fill in your keys
uvicorn salesbuff.api:app --port 8000 --reload
Health check: curl http://127.0.0.1:8000/health → {"status":"ok"}.
There's also a CLI for quick local runs:
python -m salesbuff "Meeting the VP of Ops at Acme Health next week..."
Environment variables
Set in salesbuff/.env locally, or in the Render dashboard in production.
| Var | Required | Default | Purpose |
|---|---|---|---|
OPENAI_API_KEY |
✅ | — | Brief + facts + entity resolution |
TAVILY_API_KEY |
✅ | — | Web search + deep research |
OPENAI_MODEL |
gpt-4o-mini |
Chat model | |
COURTLISTENER_TOKEN |
— | Legal/court records (optional) | |
USAGE_MAX |
25 |
Shared-quota runs before users must bring their own keys | |
USAGE_CURRENT |
0 |
Runs already consumed (in-memory counter) | |
MAX_CASES_PER_ENTITY |
8 |
Court cases kept per company | |
TAVILY_MAX_RESULTS |
5 |
Web search results | |
TAVILY_SEARCH_DEPTH |
basic |
Tavily depth |
API
| Method | Path | Description |
|---|---|---|
POST |
/research |
Submit { "prompt": "...", "keys"?: {openai, tavily, courtlistener} } → { request_id, status, usage } |
GET |
/research/{id} |
Poll → { status, stage, progress, brief, facts, warnings, error } |
GET |
/usage |
{ used, limit, remaining } |
GET |
/health |
Liveness probe |
- Without user
keys, runs count against the sharedUSAGE_MAX(HTTP 429 when exhausted). - With valid user
keys, the run bypasses the quota and uses a throwaway client; bad keys return 400 with a clear message.
Project structure
salesbuff/
├── api.py # FastAPI app: submit/poll jobs, usage limiter
├── pipeline.py # orchestrates resolve → research → brief
├── container.py # wires adapters into the pipeline (DI)
├── config.py # env → frozen Config
├── ports/ # abstract interfaces (LLM, web, legal)
├── adapters/ # OpenAI, Tavily, CourtListener implementations
├── research/ # resolve, web, legal, deep, brief, facts
├── domain/ # prompts, framing, grounding rules, source tiers, YAML loader
├── domain_logic_sales/ # editable YAML: categories, questions, ranking, compliance
└── models/ # typed shapes: entities, findings, brief, facts
The ports/adapters split is what lets a user bring their own keys at runtime (a different adapter, same pipeline) and makes the LLM/search providers swappable.
Deploy (Render)
Use the blueprint at the repo root (../render.yaml) or set
manually:
- Root Directory:
SalesBuff - Build:
pip install -r salesbuff/requirements.txt(orpip install ".[api]"— same result viapyproject.toml) - Start:
uvicorn salesbuff.api:app --host 0.0.0.0 --port $PORT - Health check path:
/health - Instances: 1 — the job store and usage counter live in memory, so multiple instances would split state.
Set OPENAI_API_KEY and TAVILY_API_KEY (and optionally COURTLISTENER_TOKEN)
as dashboard secrets.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file salesbuff-0.1.0.tar.gz.
File metadata
- Download URL: salesbuff-0.1.0.tar.gz
- Upload date:
- Size: 52.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b86c67d0864195ff281ae7eb6da78d9189ac8174ca0f0244999d79804874cbcf
|
|
| MD5 |
42c90cd7c733ee38257b24732094734a
|
|
| BLAKE2b-256 |
0049da6cdd35e12fcac05fc511a70f09be61a0f3044dc06122336387597d2520
|
File details
Details for the file salesbuff-0.1.0-py3-none-any.whl.
File metadata
- Download URL: salesbuff-0.1.0-py3-none-any.whl
- Upload date:
- Size: 63.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5edf5d55b4b1c22f1e3411f142df13dcc732d9670a3ae9dd8f80875f9db8a7d5
|
|
| MD5 |
f6ee1303565a234bc74ed170a674efe2
|
|
| BLAKE2b-256 |
9eec4bb02c16d852d388f9338340099fc9ed1dfb1f3e870ac8b8c185f42059de
|