Files
MarketingTool/README.md
T
2026-09-05 21:19:07 +02:00

141 lines
6.7 KiB
Markdown

# ProspectOS · Maps Scout
A small, personal-use prospect workspace. It sends one search at a time to
the bundled [gosom/google-maps-scraper](https://github.com/gosom/google-maps-scraper)
worker, waits for its asynchronous job to finish, filters places already in
the local catalogue, and presents the remaining places for human review.
The interface is split into Dashboard, Discover, Prospects, Runs, and Settings
views. It includes website health and email evidence, explainable scoring,
domain ideas, suppression, CSV export, scheduled runs, rescans, and human review. It never sends outreach
automatically. Optional AI can analyse a prospect and draft a subject/email
from supplied evidence and your offer; you edit and approve the draft yourself.
From a prospect's detail drawer, **Assess with AI** stores a contact probability,
recommendation, and short evidence-grounded rationale for that specific company.
## Start the stack
```bash
cp .env.example .env
docker compose up -d --build
```
Open `http://SERVER:8000` for ProspectOS. The Maps worker is available on
`http://SERVER:8081` if you want to inspect its native Web UI.
### How the worker connects
No Google Cloud API key is required. The bundled standard worker exposes a
local REST API on the Docker network, and ProspectOS calls it directly.
The app uses `/api/v1/jobs` to queue a search, polls `/api/v1/jobs/{id}`, and
downloads `/api/v1/jobs/{id}/download` when the job finishes. Jobs are
deliberately asynchronous because a Maps scrape can take several minutes.
Only set `GMAPS_API_MODE=saas` and `GMAPS_API_KEY=...` if you deliberately
replace the bundled worker with gosom's optional SaaS edition.
A run that loses its worker connection is shown as failed with a specific
error rather than remaining stuck forever.
## Configuration
| Variable | Default | Purpose |
|---|---:|---|
| `HOST_PORT` | `8000` | Host port for ProspectOS |
| `GMAPS_HOST_PORT` | `8081` | Host port for the Maps worker admin UI |
| `GMAPS_API_MODE` | `standard` | `standard` for the bundled worker; `saas` only for the optional SaaS API |
| `GMAPS_API_KEY` | empty | Not required in standard mode; only used in SaaS mode |
| `GMAPS_REQUEST_TIMEOUT` | `900` | Maximum wait for the Maps worker in seconds; raise it for very large searches |
| `GMAPS_POLL_SECONDS` | `2` | Poll interval while a job is running |
| `OUTBOUND_USER_AGENT` | `ProspectOS/2.0 (+personal-use)` | Identifies provider HTTP requests; avoids Python's default client fingerprint |
| `DISCOVERY_BACKEND` | `gmaps` when `GMAPS_URL` is set | Set to `browser` only for the bounded public-search fallback |
| `AI_PROVIDER` | `custom` | Set to `nous` for the Nous Research Portal, or `custom` for another OpenAI-compatible endpoint |
| `AI_BASE_URL` | empty | Optional OpenAI-compatible `/chat/completions` endpoint |
| `AI_API_KEY` | empty | Optional provider key; keep server-side |
| `AI_MODEL` | empty | Model name used for evidence-grounded drafts |
### Nous Research Portal
Choose **Nous Portal · free models** in Settings, paste a Nous API key, select a
free model, save, and use **Test connection** before drafting a message. The
app uses `https://inference-api.nousresearch.com/v1` automatically and tries
the live `/models` catalog; if the catalog is unavailable it shows a stable
fallback list of the free models currently published by Nous. Availability and
model IDs can change, so refresh Settings periodically.
If a Nous request returns `ai_cloudflare_1010`, rebuild the app from the latest
source so provider requests include the explicit `ProspectOS/2.0` client
identity. The old build used Python's default `Python-urllib` fingerprint, which
can be rejected by the Portal's Cloudflare policy. This is not a Maps error and
it cannot be fixed by changing the model name. If the rebuilt app still receives
1010, test the same key from the server with the provider's documented
OpenAI-compatible endpoint and contact Nous support if the endpoint continues to
block that client; do not try to evade the security challenge.
The bundled fallback entries are LongCat 2.0, Solar Pro 4, Step 3.7 Flash,
Laguna S 2.1, Laguna XS 2.1, Ling 3.0 Flash Fin, and Ling 3.0 Flash Sante
(using the Portal's `:free` model suffix).
Hermes Agent has its own browser-based OAuth flow, but that flow stores a
Hermes refresh token and is not a portable credential for this standalone
Docker app. ProspectOS therefore uses a server-side Nous API key here. The key
is never returned by the Settings API or sent to the browser after saving.
The app stores its catalogue in the `prospect_data` Docker volume. The worker
stores its own job data in `gmaps_data`; keep both volumes if you want to retain
history. To inspect status:
```bash
docker compose ps
docker compose logs --tail=100 app
docker compose logs --tail=100 gmaps
```
## Local fallback mode
For a quick local smoke test without the Maps worker:
```bash
DISCOVERY_BACKEND=browser GMAPS_URL= docker compose up -d --build
```
This uses Playwright against public search engines, keeps the same catalogue
and review UI, and does not bypass CAPTCHAs or other access controls.
## Data and review behavior
Each saved place includes its name, Maps link, website (when present), root
domain, address, phone, category, rating, review count, public emails returned
by the worker when available, source ID, and raw result JSON. A place
with no website is still retained using a stable `maps:<place_id>` catalogue
key, so it can be reviewed as a potential website opportunity. Existing
websites are deduplicated by root domain.
Email extraction is always enabled. The worker may visit each public business
website found by Maps; expect longer runs and review the resulting provenance
before using any contact information. It does not invent email addresses when
none are published.
Website scans are bounded and SSRF-safe. A scan records HTTP status, final URL,
latency, HTTPS/TLS, title, technology hints, contact-page emails, and errors.
Use `/api/prospects/{id}/scan` for a manual rescan. The explorer's “Draft AI
email” action calls `/api/prospects/{id}/message`, and **Assess with AI** calls
`/api/prospects/{id}/assess`; both require the optional AI
variables above and accepts your exact offer/instructions (for example, the
Gold Plus R119/month plan and a free rebuild). Suppressions are enforced before
new records are saved and can be managed through `/api/suppressions`.
## Tests
```bash
python3 -m py_compile api/server.py
node --check web/app.js
python3 -m unittest discover -s tests -q
```
This project is packaged for personal research. Public availability does not
override a website's terms, robots controls, or applicable privacy law; keep
searches small, use the worker only on data you are permitted to collect, and
do not turn the review screen into unattended outreach.