reheat 0.0.1__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.
- reheat-0.0.1/.gitignore +1 -0
- reheat-0.0.1/PKG-INFO +263 -0
- reheat-0.0.1/README.md +189 -0
- reheat-0.0.1/docs/_config.yml +10 -0
- reheat-0.0.1/docs/index.md +74 -0
- reheat-0.0.1/reheat/__init__.py +0 -0
- reheat-0.0.1/reheat/__main__.py +46 -0
- reheat-0.0.1/reheat/registry.py +34 -0
- reheat-0.0.1/reheat/sources/__init__.py +24 -0
- reheat-0.0.1/reheat/sources/base.py +51 -0
- reheat-0.0.1/reheat/sources/google_search_console.py +158 -0
- reheat-0.0.1/reheat/sources/serp.py +131 -0
- reheat-0.0.1/reheat/state/__init__.py +53 -0
- reheat-0.0.1/reheat/state/execution.py +381 -0
- reheat-0.0.1/reheat/state/user.py +31 -0
- reheat-0.0.1/reheat.egg-info/PKG-INFO +263 -0
- reheat-0.0.1/reheat.egg-info/SOURCES.txt +21 -0
- reheat-0.0.1/reheat.egg-info/dependency_links.txt +1 -0
- reheat-0.0.1/reheat.egg-info/entry_points.txt +2 -0
- reheat-0.0.1/reheat.egg-info/requires.txt +44 -0
- reheat-0.0.1/reheat.egg-info/top_level.txt +1 -0
- reheat-0.0.1/setup.cfg +4 -0
- reheat-0.0.1/setup.py +89 -0
reheat-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__pycache__/
|
reheat-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reheat
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Python CLI for SEO analysis. Cluster search intent, surface content gaps.
|
|
5
|
+
Home-page: https://www.bayis.co.uk/reheat
|
|
6
|
+
Author: Edward Grundy
|
|
7
|
+
Author-email: ed@bayis.co.uk
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Source, https://github.com/bayinfosys/reheat
|
|
10
|
+
Project-URL: PyPI, https://pypi.org/project/reheat
|
|
11
|
+
Project-URL: Company, https://bayis.co.uk
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
19
|
+
Classifier: Environment :: Console
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: pydantic>=2.0
|
|
25
|
+
Requires-Dist: dynawrap
|
|
26
|
+
Requires-Dist: requests
|
|
27
|
+
Requires-Dist: fastembed
|
|
28
|
+
Requires-Dist: numpy
|
|
29
|
+
Requires-Dist: scipy
|
|
30
|
+
Requires-Dist: scikit-learn
|
|
31
|
+
Requires-Dist: umap-learn
|
|
32
|
+
Requires-Dist: google-auth
|
|
33
|
+
Requires-Dist: google-auth-httplib2
|
|
34
|
+
Requires-Dist: google-api-python-client
|
|
35
|
+
Requires-Dist: google-auth-oauthlib
|
|
36
|
+
Requires-Dist: tqdm
|
|
37
|
+
Requires-Dist: fastapi
|
|
38
|
+
Requires-Dist: uvicorn
|
|
39
|
+
Requires-Dist: python-dotenv
|
|
40
|
+
Provides-Extra: local
|
|
41
|
+
Requires-Dist: sentence-transformers; extra == "local"
|
|
42
|
+
Requires-Dist: torch; extra == "local"
|
|
43
|
+
Provides-Extra: openai
|
|
44
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
45
|
+
Provides-Extra: anthropic
|
|
46
|
+
Requires-Dist: anthropic>=0.20; extra == "anthropic"
|
|
47
|
+
Provides-Extra: postgres
|
|
48
|
+
Requires-Dist: psycopg2-binary; extra == "postgres"
|
|
49
|
+
Provides-Extra: dev
|
|
50
|
+
Requires-Dist: build; extra == "dev"
|
|
51
|
+
Requires-Dist: twine; extra == "dev"
|
|
52
|
+
Requires-Dist: setuptools-scm; extra == "dev"
|
|
53
|
+
Requires-Dist: black; extra == "dev"
|
|
54
|
+
Requires-Dist: flake8; extra == "dev"
|
|
55
|
+
Requires-Dist: isort; extra == "dev"
|
|
56
|
+
Provides-Extra: all
|
|
57
|
+
Requires-Dist: sentence-transformers; extra == "all"
|
|
58
|
+
Requires-Dist: torch; extra == "all"
|
|
59
|
+
Requires-Dist: openai>=1.0; extra == "all"
|
|
60
|
+
Requires-Dist: anthropic>=0.20; extra == "all"
|
|
61
|
+
Requires-Dist: psycopg2-binary; extra == "all"
|
|
62
|
+
Dynamic: author
|
|
63
|
+
Dynamic: author-email
|
|
64
|
+
Dynamic: classifier
|
|
65
|
+
Dynamic: description
|
|
66
|
+
Dynamic: description-content-type
|
|
67
|
+
Dynamic: home-page
|
|
68
|
+
Dynamic: license
|
|
69
|
+
Dynamic: project-url
|
|
70
|
+
Dynamic: provides-extra
|
|
71
|
+
Dynamic: requires-dist
|
|
72
|
+
Dynamic: requires-python
|
|
73
|
+
Dynamic: summary
|
|
74
|
+
|
|
75
|
+
# Reheat
|
|
76
|
+
|
|
77
|
+
Python CLI for SEO analysis. Pulls search queries from Google Search Console,
|
|
78
|
+
enriches them with related searches and People Also Ask data, clusters by
|
|
79
|
+
semantic intent, and surfaces content gaps and opportunities.
|
|
80
|
+
|
|
81
|
+
Built by [Edward Grundy](https://bayis.co.uk) at
|
|
82
|
+
[Bay Information Systems](https://bayis.co.uk).
|
|
83
|
+
|
|
84
|
+
- Install: `pip install reheat`
|
|
85
|
+
- Docs: [bayinfosys.github.io/reheat](https://bayinfosys.github.io/reheat)
|
|
86
|
+
- PyPI: [pypi.org/project/reheat](https://pypi.org/project/reheat)
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Getting started
|
|
91
|
+
|
|
92
|
+
### Install
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install reheat
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Requires Python 3.10+. For the local web interface you also need a running
|
|
99
|
+
postgres instance (or use the JSON file backend for local development
|
|
100
|
+
without postgres).
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
docker run -d \
|
|
104
|
+
--name reheat-pg \
|
|
105
|
+
-e POSTGRES_USER=reheat \
|
|
106
|
+
-e POSTGRES_PASSWORD=reheat \
|
|
107
|
+
-e POSTGRES_DB=reheat \
|
|
108
|
+
-p 5432:5432 \
|
|
109
|
+
postgres:16
|
|
110
|
+
|
|
111
|
+
export DATABASE_URL=postgresql://reheat:reheat@localhost:5432/reheat
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Configure a Google Search Console source
|
|
115
|
+
|
|
116
|
+
Download OAuth2 credentials from Google Cloud Console (APIs and Services >
|
|
117
|
+
Credentials > OAuth 2.0 Client IDs, Desktop app type) and save as
|
|
118
|
+
`~/.reheat/google-search-console.json`. Then:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
reheat sources create \
|
|
122
|
+
--source-type google_search_console \
|
|
123
|
+
--domain yourdomain.com \
|
|
124
|
+
--client-secrets-path ~/.reheat/google-search-console.json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Authenticate
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
reheat sources auth
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Opens a browser for the Google OAuth2 consent flow. The token is persisted
|
|
134
|
+
to `~/.reheat/gsc_token.json` and refreshed automatically on subsequent runs.
|
|
135
|
+
|
|
136
|
+
### Configure a SerpAPI source (optional)
|
|
137
|
+
|
|
138
|
+
Required for PAA and related search enrichment. Get an API key at
|
|
139
|
+
[serpapi.com](https://serpapi.com).
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
reheat sources create \
|
|
143
|
+
--source-type serp \
|
|
144
|
+
--api-key YOUR_SERP_API_KEY
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Run the pipeline
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Fetch queries from Search Console
|
|
151
|
+
reheat runs create
|
|
152
|
+
|
|
153
|
+
# Enrich and process
|
|
154
|
+
reheat enrich tags
|
|
155
|
+
reheat enrich embed
|
|
156
|
+
reheat enrich cluster
|
|
157
|
+
reheat enrich gap
|
|
158
|
+
reheat analyse opportunities
|
|
159
|
+
|
|
160
|
+
# Build report data
|
|
161
|
+
reheat project create
|
|
162
|
+
reheat report scatter create
|
|
163
|
+
reheat report summary create
|
|
164
|
+
reheat report coverage create
|
|
165
|
+
|
|
166
|
+
# Start the web interface
|
|
167
|
+
reheat serve
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Open [http://localhost:8000](http://localhost:8000).
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Inference providers
|
|
175
|
+
|
|
176
|
+
`reheat analyse summarise` labels intent clusters using an LLM. Configure
|
|
177
|
+
one of the following.
|
|
178
|
+
|
|
179
|
+
### OpenAI
|
|
180
|
+
|
|
181
|
+
Set `OPENAI_API_KEY` in your environment or `.env` file, or:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
reheat config set --key openai_api_key --value sk-...
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Anthropic
|
|
188
|
+
|
|
189
|
+
Set `ANTHROPIC_API_KEY` in your environment or `.env` file, or:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
reheat config set --key anthropic_api_key --value sk-ant-...
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Marigold
|
|
196
|
+
|
|
197
|
+
[Marigold](https://marigold.run) is a private inference API built by
|
|
198
|
+
Bay Information Systems. Set endpoint and key when available:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
reheat config set --key marigold_endpoint --value https://api.marigold.run
|
|
202
|
+
reheat config set --key marigold_api_key --value <key>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## CLI reference
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
reheat config show / set
|
|
211
|
+
reheat sources create / list / show / update / delete / auth
|
|
212
|
+
reheat runs create / list / show / delete
|
|
213
|
+
reheat enrichments list / show / delete
|
|
214
|
+
reheat enrich tags / embed / cluster / gap
|
|
215
|
+
reheat analyse summarise / opportunities
|
|
216
|
+
reheat project create / read
|
|
217
|
+
reheat report scatter / summary / coverage create / read
|
|
218
|
+
reheat serve
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Architecture
|
|
224
|
+
|
|
225
|
+
reheat has three layers.
|
|
226
|
+
|
|
227
|
+
**Commands** in `reheat/commands/` are the single source of truth for the
|
|
228
|
+
application surface. Each command is a Python function decorated with
|
|
229
|
+
`@command`, registered in a central registry, and exposed automatically
|
|
230
|
+
through both the CLI and the HTTP API.
|
|
231
|
+
|
|
232
|
+
**Pipeline** functions in `reheat/pipeline/` are pure data transforms:
|
|
233
|
+
embedding, clustering, gap analysis, report building. No persistence, no
|
|
234
|
+
side effects.
|
|
235
|
+
|
|
236
|
+
**Persistence** uses [dynawrap](https://github.com/bayinfosys/dynawrap),
|
|
237
|
+
a lightweight key-value library with identical interfaces over PostgreSQL
|
|
238
|
+
and DynamoDB. Tables are passed at call time; models are backend-agnostic.
|
|
239
|
+
|
|
240
|
+
The web interface is a static SPA served by FastAPI. All pages share a
|
|
241
|
+
single stylesheet and a common `api.js` module that is the single source
|
|
242
|
+
of truth for API endpoint calls.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Requirements
|
|
247
|
+
|
|
248
|
+
- Python 3.10+
|
|
249
|
+
- PostgreSQL (or JSON file backend for local development)
|
|
250
|
+
- Google Search Console OAuth2 credentials
|
|
251
|
+
- SerpAPI key (optional, for PAA enrichment)
|
|
252
|
+
- OpenAI, Anthropic, or Marigold key (optional, for cluster summarisation)
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT. See [LICENSE](LICENSE).
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
Built by [Edward Grundy](https://bayis.co.uk) --
|
|
263
|
+
[Bay Information Systems](https://bayis.co.uk)
|
reheat-0.0.1/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Reheat
|
|
2
|
+
|
|
3
|
+
Python CLI for SEO analysis. Pulls search queries from Google Search Console,
|
|
4
|
+
enriches them with related searches and People Also Ask data, clusters by
|
|
5
|
+
semantic intent, and surfaces content gaps and opportunities.
|
|
6
|
+
|
|
7
|
+
Built by [Edward Grundy](https://bayis.co.uk) at
|
|
8
|
+
[Bay Information Systems](https://bayis.co.uk).
|
|
9
|
+
|
|
10
|
+
- Install: `pip install reheat`
|
|
11
|
+
- Docs: [bayinfosys.github.io/reheat](https://bayinfosys.github.io/reheat)
|
|
12
|
+
- PyPI: [pypi.org/project/reheat](https://pypi.org/project/reheat)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Getting started
|
|
17
|
+
|
|
18
|
+
### Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install reheat
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires Python 3.10+. For the local web interface you also need a running
|
|
25
|
+
postgres instance (or use the JSON file backend for local development
|
|
26
|
+
without postgres).
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
docker run -d \
|
|
30
|
+
--name reheat-pg \
|
|
31
|
+
-e POSTGRES_USER=reheat \
|
|
32
|
+
-e POSTGRES_PASSWORD=reheat \
|
|
33
|
+
-e POSTGRES_DB=reheat \
|
|
34
|
+
-p 5432:5432 \
|
|
35
|
+
postgres:16
|
|
36
|
+
|
|
37
|
+
export DATABASE_URL=postgresql://reheat:reheat@localhost:5432/reheat
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Configure a Google Search Console source
|
|
41
|
+
|
|
42
|
+
Download OAuth2 credentials from Google Cloud Console (APIs and Services >
|
|
43
|
+
Credentials > OAuth 2.0 Client IDs, Desktop app type) and save as
|
|
44
|
+
`~/.reheat/google-search-console.json`. Then:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
reheat sources create \
|
|
48
|
+
--source-type google_search_console \
|
|
49
|
+
--domain yourdomain.com \
|
|
50
|
+
--client-secrets-path ~/.reheat/google-search-console.json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Authenticate
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
reheat sources auth
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Opens a browser for the Google OAuth2 consent flow. The token is persisted
|
|
60
|
+
to `~/.reheat/gsc_token.json` and refreshed automatically on subsequent runs.
|
|
61
|
+
|
|
62
|
+
### Configure a SerpAPI source (optional)
|
|
63
|
+
|
|
64
|
+
Required for PAA and related search enrichment. Get an API key at
|
|
65
|
+
[serpapi.com](https://serpapi.com).
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
reheat sources create \
|
|
69
|
+
--source-type serp \
|
|
70
|
+
--api-key YOUR_SERP_API_KEY
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Run the pipeline
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Fetch queries from Search Console
|
|
77
|
+
reheat runs create
|
|
78
|
+
|
|
79
|
+
# Enrich and process
|
|
80
|
+
reheat enrich tags
|
|
81
|
+
reheat enrich embed
|
|
82
|
+
reheat enrich cluster
|
|
83
|
+
reheat enrich gap
|
|
84
|
+
reheat analyse opportunities
|
|
85
|
+
|
|
86
|
+
# Build report data
|
|
87
|
+
reheat project create
|
|
88
|
+
reheat report scatter create
|
|
89
|
+
reheat report summary create
|
|
90
|
+
reheat report coverage create
|
|
91
|
+
|
|
92
|
+
# Start the web interface
|
|
93
|
+
reheat serve
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Open [http://localhost:8000](http://localhost:8000).
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Inference providers
|
|
101
|
+
|
|
102
|
+
`reheat analyse summarise` labels intent clusters using an LLM. Configure
|
|
103
|
+
one of the following.
|
|
104
|
+
|
|
105
|
+
### OpenAI
|
|
106
|
+
|
|
107
|
+
Set `OPENAI_API_KEY` in your environment or `.env` file, or:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
reheat config set --key openai_api_key --value sk-...
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Anthropic
|
|
114
|
+
|
|
115
|
+
Set `ANTHROPIC_API_KEY` in your environment or `.env` file, or:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
reheat config set --key anthropic_api_key --value sk-ant-...
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Marigold
|
|
122
|
+
|
|
123
|
+
[Marigold](https://marigold.run) is a private inference API built by
|
|
124
|
+
Bay Information Systems. Set endpoint and key when available:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
reheat config set --key marigold_endpoint --value https://api.marigold.run
|
|
128
|
+
reheat config set --key marigold_api_key --value <key>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## CLI reference
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
reheat config show / set
|
|
137
|
+
reheat sources create / list / show / update / delete / auth
|
|
138
|
+
reheat runs create / list / show / delete
|
|
139
|
+
reheat enrichments list / show / delete
|
|
140
|
+
reheat enrich tags / embed / cluster / gap
|
|
141
|
+
reheat analyse summarise / opportunities
|
|
142
|
+
reheat project create / read
|
|
143
|
+
reheat report scatter / summary / coverage create / read
|
|
144
|
+
reheat serve
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Architecture
|
|
150
|
+
|
|
151
|
+
reheat has three layers.
|
|
152
|
+
|
|
153
|
+
**Commands** in `reheat/commands/` are the single source of truth for the
|
|
154
|
+
application surface. Each command is a Python function decorated with
|
|
155
|
+
`@command`, registered in a central registry, and exposed automatically
|
|
156
|
+
through both the CLI and the HTTP API.
|
|
157
|
+
|
|
158
|
+
**Pipeline** functions in `reheat/pipeline/` are pure data transforms:
|
|
159
|
+
embedding, clustering, gap analysis, report building. No persistence, no
|
|
160
|
+
side effects.
|
|
161
|
+
|
|
162
|
+
**Persistence** uses [dynawrap](https://github.com/bayinfosys/dynawrap),
|
|
163
|
+
a lightweight key-value library with identical interfaces over PostgreSQL
|
|
164
|
+
and DynamoDB. Tables are passed at call time; models are backend-agnostic.
|
|
165
|
+
|
|
166
|
+
The web interface is a static SPA served by FastAPI. All pages share a
|
|
167
|
+
single stylesheet and a common `api.js` module that is the single source
|
|
168
|
+
of truth for API endpoint calls.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Requirements
|
|
173
|
+
|
|
174
|
+
- Python 3.10+
|
|
175
|
+
- PostgreSQL (or JSON file backend for local development)
|
|
176
|
+
- Google Search Console OAuth2 credentials
|
|
177
|
+
- SerpAPI key (optional, for PAA enrichment)
|
|
178
|
+
- OpenAI, Anthropic, or Marigold key (optional, for cluster summarisation)
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT. See [LICENSE](LICENSE).
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
Built by [Edward Grundy](https://bayis.co.uk) --
|
|
189
|
+
[Bay Information Systems](https://bayis.co.uk)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
title: reheat
|
|
2
|
+
description: >
|
|
3
|
+
Open source Python CLI for SEO analysis. Pull Google Search Console queries,
|
|
4
|
+
cluster by semantic intent, and surface content gaps and opportunities.
|
|
5
|
+
url: https://bayinfosys.github.io
|
|
6
|
+
baseurl: /reheat
|
|
7
|
+
theme: minima
|
|
8
|
+
author:
|
|
9
|
+
name: Edward Grundy
|
|
10
|
+
url: https://bayis.co.uk
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: reheat
|
|
4
|
+
description: >
|
|
5
|
+
reheat is an open source Python CLI for SEO analysis. Pull queries from
|
|
6
|
+
Google Search Console, cluster by intent, and surface content gaps.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# reheat
|
|
10
|
+
|
|
11
|
+
Open source Python CLI for SEO analysis. Pull your Google Search Console
|
|
12
|
+
queries, enrich them with related searches and People Also Ask data, cluster
|
|
13
|
+
by semantic intent, and surface content gaps and opportunities.
|
|
14
|
+
|
|
15
|
+
Built by [Edward Grundy](https://bayis.co.uk) at
|
|
16
|
+
[Bay Information Systems](https://bayis.co.uk).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install reheat
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Requires Python 3.10+.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Configure your Search Console source
|
|
34
|
+
reheat sources create \
|
|
35
|
+
--source-type google_search_console \
|
|
36
|
+
--domain yourdomain.com \
|
|
37
|
+
--client-secrets-path ~/.reheat/google-search-console.json
|
|
38
|
+
|
|
39
|
+
# Authenticate
|
|
40
|
+
reheat sources auth
|
|
41
|
+
|
|
42
|
+
# Run the pipeline
|
|
43
|
+
reheat runs create
|
|
44
|
+
reheat enrich tags
|
|
45
|
+
reheat enrich embed
|
|
46
|
+
reheat enrich cluster
|
|
47
|
+
reheat enrich gap
|
|
48
|
+
reheat analyse opportunities
|
|
49
|
+
reheat project create
|
|
50
|
+
reheat report scatter create
|
|
51
|
+
reheat report summary create
|
|
52
|
+
reheat report coverage create
|
|
53
|
+
|
|
54
|
+
# Open the web interface
|
|
55
|
+
reheat serve
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Inference providers
|
|
61
|
+
|
|
62
|
+
Cluster summarisation (`reheat analyse summarise`) works with
|
|
63
|
+
[OpenAI](https://openai.com), [Anthropic](https://anthropic.com), or
|
|
64
|
+
[Marigold](https://marigold.run). Set the relevant API key in your
|
|
65
|
+
environment or `.env` file and reheat will pick it up automatically.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Links
|
|
70
|
+
|
|
71
|
+
- [GitHub repository](https://github.com/bayinfosys/reheat)
|
|
72
|
+
- [PyPI](https://pypi.org/project/reheat)
|
|
73
|
+
- [Bay Information Systems](https://bayis.co.uk)
|
|
74
|
+
- [dynawrap](https://github.com/bayinfosys/dynawrap) -- persistence layer
|
|
File without changes
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from reheat.state import init_backend
|
|
5
|
+
|
|
6
|
+
import reheat.commands.config
|
|
7
|
+
import reheat.commands.sources
|
|
8
|
+
import reheat.commands.runs
|
|
9
|
+
import reheat.commands.enrichments
|
|
10
|
+
import reheat.commands.enrich
|
|
11
|
+
import reheat.commands.analyse
|
|
12
|
+
import reheat.commands.project
|
|
13
|
+
import reheat.commands.report
|
|
14
|
+
import reheat.commands.serve
|
|
15
|
+
|
|
16
|
+
from reheat.adapters.argparse_adapter import build_parser, dispatch
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
parser = build_parser()
|
|
21
|
+
args = parser.parse_args()
|
|
22
|
+
|
|
23
|
+
logging.basicConfig(
|
|
24
|
+
format="%(asctime)s %(levelname)-8s %(name)s: %(message)s",
|
|
25
|
+
datefmt="%H:%M:%S",
|
|
26
|
+
level=logging.DEBUG if getattr(args, "verbose", False) else logging.INFO,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
backend = init_backend(getattr(args, "config", None))
|
|
31
|
+
except Exception as e:
|
|
32
|
+
print(f"error: failed to initialise backend: {e}")
|
|
33
|
+
sys.exit(1)
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
dispatch(args, backend)
|
|
37
|
+
except KeyboardInterrupt:
|
|
38
|
+
print("\ninterrupted")
|
|
39
|
+
sys.exit(130)
|
|
40
|
+
except Exception:
|
|
41
|
+
logging.getLogger(__name__).exception("command failed")
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
main()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import TypeVar, Generic, Callable, Dict, Optional
|
|
2
|
+
|
|
3
|
+
T = TypeVar("T")
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Resource(Generic[T]):
|
|
7
|
+
"""Parameter is a resource identifier. Maps to a URL path segment."""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Payload(Generic[T]):
|
|
12
|
+
"""Parameter is request payload. Maps to a POST body field."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
_registry: Dict[str, Callable] = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def command(help: str = "", interactive_only: bool = False):
|
|
20
|
+
def decorator(fn: Callable) -> Callable:
|
|
21
|
+
parts = fn.__name__.split("_")
|
|
22
|
+
|
|
23
|
+
if parts[0] != "cmd":
|
|
24
|
+
raise ValueError(f"command functions must start with cmd_, got {fn.__name__}")
|
|
25
|
+
|
|
26
|
+
path = ".".join(parts[1:])
|
|
27
|
+
_registry[path] = fn
|
|
28
|
+
fn._cli_path = path
|
|
29
|
+
fn._cli_help = help
|
|
30
|
+
fn._interactive_only = interactive_only
|
|
31
|
+
|
|
32
|
+
return fn
|
|
33
|
+
|
|
34
|
+
return decorator
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from reheat.state.execution import SourceConfig
|
|
2
|
+
from reheat.sources.base import SourceProvider, SourceError
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_source_provider(config: SourceConfig) -> SourceProvider:
|
|
6
|
+
"""
|
|
7
|
+
Factory: construct the correct SourceProvider for a SourceConfig.
|
|
8
|
+
Importing here keeps the registry central and avoids circular imports.
|
|
9
|
+
"""
|
|
10
|
+
from reheat.sources.google_search_console import GoogleSearchConsoleProvider
|
|
11
|
+
from reheat.sources.serp import SerpAPIProvider
|
|
12
|
+
|
|
13
|
+
providers = {
|
|
14
|
+
"google_search_console": GoogleSearchConsoleProvider,
|
|
15
|
+
"serp": SerpAPIProvider,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
cls = providers.get(config.source_type)
|
|
19
|
+
if cls is None:
|
|
20
|
+
raise SourceError(
|
|
21
|
+
f"unknown source type {config.source_type!r}. "
|
|
22
|
+
f"Available: {', '.join(providers)}"
|
|
23
|
+
)
|
|
24
|
+
return cls(config)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
|
+
from reheat.state.execution import QueryRecord, SourceConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SourceProvider(ABC):
|
|
7
|
+
"""
|
|
8
|
+
Base class for data source providers.
|
|
9
|
+
|
|
10
|
+
Each provider knows how to:
|
|
11
|
+
- validate its configuration
|
|
12
|
+
- execute a fetch and return QueryRecords
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
source_type: str = ""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config: SourceConfig) -> None:
|
|
18
|
+
self.config = config
|
|
19
|
+
self.validate()
|
|
20
|
+
|
|
21
|
+
def validate(self) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Raise ValueError if the SourceConfig is missing required credentials
|
|
24
|
+
or settings. Called at construction time.
|
|
25
|
+
"""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def fetch(self) -> List[QueryRecord]:
|
|
30
|
+
"""
|
|
31
|
+
Pull data from the source and return QueryRecords.
|
|
32
|
+
Raises SourceError on failure.
|
|
33
|
+
"""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def _credential(self, key: str) -> str:
|
|
37
|
+
"""Return a credential value, raising ValueError if absent."""
|
|
38
|
+
value = self.config.credentials.get(key, "")
|
|
39
|
+
if not value:
|
|
40
|
+
raise ValueError(
|
|
41
|
+
f"source {self.config.source_id!r} missing credential {key!r}"
|
|
42
|
+
)
|
|
43
|
+
return value
|
|
44
|
+
|
|
45
|
+
def _setting(self, key: str, default: Any = None) -> Any:
|
|
46
|
+
"""Return a setting value with optional default."""
|
|
47
|
+
return self.config.settings.get(key, default)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class SourceError(Exception):
|
|
51
|
+
"""Raised when a source provider fails to fetch data."""
|