128 lines
5.8 KiB
Markdown
128 lines
5.8 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.
|
|
|
|
## 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 |
|
|
| `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.
|
|
|
|
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`; it requires 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.
|