autofeeder 0.1.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.
- autofeeder-0.1.1/PKG-INFO +333 -0
- autofeeder-0.1.1/README.md +310 -0
- autofeeder-0.1.1/autofeeder.egg-info/PKG-INFO +333 -0
- autofeeder-0.1.1/autofeeder.egg-info/SOURCES.txt +49 -0
- autofeeder-0.1.1/autofeeder.egg-info/dependency_links.txt +1 -0
- autofeeder-0.1.1/autofeeder.egg-info/entry_points.txt +2 -0
- autofeeder-0.1.1/autofeeder.egg-info/requires.txt +19 -0
- autofeeder-0.1.1/autofeeder.egg-info/top_level.txt +1 -0
- autofeeder-0.1.1/pyproject.toml +46 -0
- autofeeder-0.1.1/rss_reader/__init__.py +1 -0
- autofeeder-0.1.1/rss_reader/app.py +322 -0
- autofeeder-0.1.1/rss_reader/backup.py +80 -0
- autofeeder-0.1.1/rss_reader/catalog.py +234 -0
- autofeeder-0.1.1/rss_reader/catalog_providers.py +459 -0
- autofeeder-0.1.1/rss_reader/chunker.py +29 -0
- autofeeder-0.1.1/rss_reader/data/catalog_snapshots/apis.json +1 -0
- autofeeder-0.1.1/rss_reader/data/catalog_snapshots/feeds.json +1 -0
- autofeeder-0.1.1/rss_reader/data/catalog_snapshots/websites.json +1 -0
- autofeeder-0.1.1/rss_reader/data/source_catalog.json +71 -0
- autofeeder-0.1.1/rss_reader/database.py +1624 -0
- autofeeder-0.1.1/rss_reader/duckstore.py +846 -0
- autofeeder-0.1.1/rss_reader/embeddings.py +229 -0
- autofeeder-0.1.1/rss_reader/extractor.py +166 -0
- autofeeder-0.1.1/rss_reader/feeds.py +123 -0
- autofeeder-0.1.1/rss_reader/fetchers.py +445 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/index-C91Lco4U.js +13 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/assets/index-CuFzDjkd.css +1 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/favicon.svg +9 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/icons.svg +24 -0
- autofeeder-0.1.1/rss_reader/frontend_dist/index.html +23 -0
- autofeeder-0.1.1/rss_reader/json_mapping.py +64 -0
- autofeeder-0.1.1/rss_reader/llm.py +81 -0
- autofeeder-0.1.1/rss_reader/pipeline.py +1309 -0
- autofeeder-0.1.1/rss_reader/publish.py +386 -0
- autofeeder-0.1.1/rss_reader/session_store.py +87 -0
- autofeeder-0.1.1/rss_reader/vectorstore.py +115 -0
- autofeeder-0.1.1/rss_reader/web.py +2309 -0
- autofeeder-0.1.1/rss_reader/website.py +427 -0
- autofeeder-0.1.1/setup.cfg +4 -0
- autofeeder-0.1.1/tests/test_catalog.py +185 -0
- autofeeder-0.1.1/tests/test_core.py +77 -0
- autofeeder-0.1.1/tests/test_extraction_features.py +466 -0
- autofeeder-0.1.1/tests/test_llm.py +30 -0
- autofeeder-0.1.1/tests/test_pipeline.py +282 -0
- autofeeder-0.1.1/tests/test_production.py +74 -0
- autofeeder-0.1.1/tests/test_publish.py +116 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autofeeder
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Autofeeder local feed, web, and API extraction app
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
8
|
+
Requires-Dist: duckdb>=1.1
|
|
9
|
+
Requires-Dist: feedparser>=6.0
|
|
10
|
+
Requires-Dist: flask>=3.0
|
|
11
|
+
Requires-Dist: jsonschema>=4.23
|
|
12
|
+
Requires-Dist: requests>=2.31
|
|
13
|
+
Requires-Dist: trafilatura>=2.2
|
|
14
|
+
Provides-Extra: browser
|
|
15
|
+
Requires-Dist: playwright>=1.62; extra == "browser"
|
|
16
|
+
Provides-Extra: sync
|
|
17
|
+
Requires-Dist: psycopg[binary]>=3.1; extra == "sync"
|
|
18
|
+
Requires-Dist: pymysql>=1.1; extra == "sync"
|
|
19
|
+
Requires-Dist: pymssql>=2.3; extra == "sync"
|
|
20
|
+
Requires-Dist: oracledb>=2.4; extra == "sync"
|
|
21
|
+
Provides-Extra: embeddings
|
|
22
|
+
Requires-Dist: sentence-transformers>=3; extra == "embeddings"
|
|
23
|
+
|
|
24
|
+
# Autofeeder
|
|
25
|
+
|
|
26
|
+
> **Local-first intelligence extraction.** Point it at RSS feeds, websites, or APIs. Define what you want to pull out. Get a structured DuckDB table on your machine — no cloud, no accounts, no data leaving your box.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
One command. Opens in your browser when done. Works on macOS, Linux, and Windows — including locked-down enterprise machines.
|
|
33
|
+
|
|
34
|
+
### macOS / Linux
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
curl -fsSL https://raw.githubusercontent.com/arunavdaniel/Autofeeder/main/install.sh | sh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Windows (PowerShell)
|
|
41
|
+
|
|
42
|
+
```powershell
|
|
43
|
+
iwr -useb https://raw.githubusercontent.com/arunavdaniel/Autofeeder/main/install.ps1 | iex
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### No `curl`? Any machine with Python works
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
python3 install.py
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> Download [`install.py`](https://raw.githubusercontent.com/arunavdaniel/Autofeeder/main/install.py) first, then run it. That's it.
|
|
53
|
+
|
|
54
|
+
After install, Autofeeder starts automatically and opens **http://127.0.0.1:8765** in your browser.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## What it does
|
|
59
|
+
|
|
60
|
+
Autofeeder is an end-to-end extraction pipeline that runs entirely on your machine:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
SOURCES → FETCH → SNAPSHOT → TEXT EXTRACTION → LLM → DUCKDB
|
|
64
|
+
RSS HTTP/browser trafilatura any queryable
|
|
65
|
+
Atom or Playwright clean text OpenAI- structured
|
|
66
|
+
Websites compat table
|
|
67
|
+
APIs
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
1. **Subscribe to sources** — RSS/Atom feeds, arbitrary public websites, or JSON APIs. Group into folders.
|
|
71
|
+
2. **Snapshot** — Capture a reproducible point-in-time set of articles.
|
|
72
|
+
3. **Extract text** — Pull clean readable body text from raw HTML using trafilatura.
|
|
73
|
+
4. **Define a schema** — Describe what structured fields you want out of each article (name, type, description).
|
|
74
|
+
5. **Run LLM extraction** — Send article text + your prompt to any OpenAI-compatible model. Get validated JSON back.
|
|
75
|
+
6. **Write to DuckDB** — Records land in a local DuckDB table with metadata columns stamped automatically.
|
|
76
|
+
7. **Query** — Open the built-in SQL viewer, run any query, export to CSV/Parquet/JSON.
|
|
77
|
+
8. **Automate** — Schedule any pipeline on an interval or daily timer.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## What you can build with it
|
|
82
|
+
|
|
83
|
+
| Use case | What you do |
|
|
84
|
+
|---|---|
|
|
85
|
+
| **Market intelligence** | Subscribe to trade press, extract competitor pricing/announcements → queryable DuckDB table |
|
|
86
|
+
| **Research database** | Turn newsletters and blogs into structured facts you can `JOIN` and `GROUP BY` |
|
|
87
|
+
| **Knowledge base** | Feed a source list → chunk → embed → semantic search, all local |
|
|
88
|
+
| **Dataset creation** | Build schema-conforming labeled datasets for fine-tuning from web sources |
|
|
89
|
+
| **Website monitoring** | Watch public pages for meaningful changes, review diffs, trigger extraction on change |
|
|
90
|
+
| **Local LLM pipeline** | Point at Ollama or LM Studio — nothing leaves your machine, no API keys required |
|
|
91
|
+
| **Scheduled feeds** | Snapshot + schedule → rolling DuckDB table updated automatically on a timer |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Installer options
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Skip Playwright browser download (faster; JS-heavy article fetching unavailable)
|
|
99
|
+
python3 install.py --no-browser
|
|
100
|
+
|
|
101
|
+
# Custom install location
|
|
102
|
+
python3 install.py --dir /opt/autofeeder
|
|
103
|
+
|
|
104
|
+
# Install a specific version
|
|
105
|
+
python3 install.py --version 0.2.1
|
|
106
|
+
|
|
107
|
+
# Corporate SSL inspection / custom CA certificate
|
|
108
|
+
python3 install.py --ca-bundle /etc/ssl/corporate-ca.pem
|
|
109
|
+
|
|
110
|
+
# Fully offline / air-gapped — requires a pre-downloaded bundle zip
|
|
111
|
+
python3 install.py --offline --bundle ~/Downloads/autofeeder-bundle.zip
|
|
112
|
+
|
|
113
|
+
# Preview what would happen without making any changes
|
|
114
|
+
python3 install.py --dry-run
|
|
115
|
+
|
|
116
|
+
# Uninstall
|
|
117
|
+
python3 install.py --uninstall
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Enterprise compatibility
|
|
121
|
+
|
|
122
|
+
The installer works on locked-down machines with no admin rights:
|
|
123
|
+
|
|
124
|
+
| Restriction | How it's handled |
|
|
125
|
+
|---|---|
|
|
126
|
+
| No admin / sudo | Installs entirely to `~/.autofeeder/` in your home directory |
|
|
127
|
+
| No `git` | Downloads a source zip from GitHub releases or from PyPI |
|
|
128
|
+
| No `curl` / `wget` | Falls back to Python's built-in `urllib` automatically |
|
|
129
|
+
| Python < 3.10 or missing | Downloads a portable Python 3.12 via [python-build-standalone](https://github.com/indygreg/python-build-standalone) |
|
|
130
|
+
| HTTP/HTTPS proxy | Reads `HTTP_PROXY` / `HTTPS_PROXY` env vars |
|
|
131
|
+
| NTLM / Kerberos proxy (Windows) | `install.ps1` uses the system proxy with default network credentials |
|
|
132
|
+
| Corporate SSL inspection | `--ca-bundle` flag or `REQUESTS_CA_BUNDLE` env var |
|
|
133
|
+
| Playwright blocked by IT | `--no-browser` — app works fully without it |
|
|
134
|
+
| Air-gapped / no internet | `--offline --bundle` with a zip pre-downloaded on another machine |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Re-running after install
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
~/.autofeeder/autofeeder # macOS / Linux
|
|
142
|
+
~/.autofeeder/autofeeder.bat # Windows
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If Autofeeder is already running, the launcher detects it and just opens your browser to `http://127.0.0.1:8765` without starting a second instance.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Features
|
|
150
|
+
|
|
151
|
+
| Page | What you can do |
|
|
152
|
+
|---|---|
|
|
153
|
+
| **Overview** | Dashboard: counts of feeds, pipelines, runs, records extracted, errors. Last run summary. |
|
|
154
|
+
| **Sources** | Add/edit/delete RSS & Atom feeds. Group into folders. Auto-refresh every 15 m / 30 m / 1 h / 6 h. Optional Playwright browser fetch for JS-heavy sites. |
|
|
155
|
+
| **Discover** | Browse a curated catalog of feeds and websites to add in one click. |
|
|
156
|
+
| **Websites** | Monitor any public URL. HTTP or Playwright. Change detection via content hash. Diff review. Feed changes into pipelines. |
|
|
157
|
+
| **Schemas** | Define reusable extraction schemas: field name, type, description, required flag, default value. |
|
|
158
|
+
| **Pipelines** | Compose a run: source → LLM endpoint + model + prompt → schema → DuckDB output (append / overwrite / upsert, dedupe key). Preview one article before saving. Retries, concurrency, timeout. |
|
|
159
|
+
| **DuckDB** | SQL viewer: browse databases, open tables, run read-only or write queries, rename/delete databases and tables. |
|
|
160
|
+
| **Embeddings** | Chunk articles into paragraphs/sentences. Embed locally (deterministic hash vectors) or via any OpenAI-compatible endpoint, Ollama, or LM Studio. |
|
|
161
|
+
| **Semantic Search** | Embed a question → cosine similarity over local chunks → results with source, title, date, matched text, URL. |
|
|
162
|
+
| **Exports** | Export DuckDB tables or query results to CSV, Parquet, JSON, SQLite. Upsert-sync to Postgres, MySQL, MSSQL, Oracle. |
|
|
163
|
+
| **Schedules** | Create interval or daily snapshot schedules with a DuckDB destination. Runs automatically in the background. |
|
|
164
|
+
| **Run History** | Per-run logs, phase-by-phase progress, errors, and extracted output for every pipeline execution. |
|
|
165
|
+
| **Stats** | Charts of runs, records written, and errors over time. |
|
|
166
|
+
| **Settings** | Dark mode, app preferences. LLM API keys and endpoints stay in browser `localStorage` only — never written to the server. |
|
|
167
|
+
|
|
168
|
+
### Pipeline stages (only use what you need)
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
SOURCE → FETCH → SNAPSHOT → CHANGE DETECTION → TEXT EXTRACTION
|
|
172
|
+
↓
|
|
173
|
+
CHUNKING → EMBEDDING → LOCAL VECTOR SEARCH
|
|
174
|
+
↓
|
|
175
|
+
LLM EXTRACTION → VALIDATION → DEDUPLICATION
|
|
176
|
+
↓
|
|
177
|
+
DUCKDB → EXPORT / REPLICATION
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### DuckDB output schema
|
|
181
|
+
|
|
182
|
+
Every extracted record carries automatic metadata columns:
|
|
183
|
+
|
|
184
|
+
```sql
|
|
185
|
+
ingested_at TIMESTAMP -- when the record was written
|
|
186
|
+
feed_title VARCHAR -- source feed or website name
|
|
187
|
+
article_url VARCHAR -- original article URL
|
|
188
|
+
run_id BIGINT -- links back to the pipeline run
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Privacy
|
|
192
|
+
|
|
193
|
+
- LLM API keys are used for the outbound request only. They are **never written to disk or the local database**.
|
|
194
|
+
- Endpoint, model, and prompt live in browser `localStorage`.
|
|
195
|
+
- No telemetry. No accounts. No network calls except to feeds and the LLM endpoint you configure.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## LLM configuration
|
|
200
|
+
|
|
201
|
+
Autofeeder works with any OpenAI-compatible chat completions endpoint:
|
|
202
|
+
|
|
203
|
+
| Provider | Endpoint |
|
|
204
|
+
|---|---|
|
|
205
|
+
| OpenAI | `https://api.openai.com/v1/chat/completions` |
|
|
206
|
+
| Ollama (local) | `http://localhost:11434/v1/chat/completions` |
|
|
207
|
+
| LM Studio (local) | `http://localhost:1234/v1/chat/completions` |
|
|
208
|
+
| Anything else | Any `POST /v1/chat/completions` compatible API |
|
|
209
|
+
|
|
210
|
+
Configure in **Settings → LLM**. The key is used only for the duration of the request.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Optional extras
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Playwright browser (for JS-heavy article fetching)
|
|
218
|
+
pip install 'autofeeder[browser]'
|
|
219
|
+
python -m playwright install chromium
|
|
220
|
+
|
|
221
|
+
# Database sync / upsert (Postgres, MySQL, MSSQL, Oracle)
|
|
222
|
+
pip install 'autofeeder[sync]'
|
|
223
|
+
|
|
224
|
+
# Sentence-level embeddings via sentence-transformers
|
|
225
|
+
pip install 'autofeeder[embeddings]'
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Connection strings: `postgres://user:pass@host:5432/db`, `mysql://user:pass@host:3306/db`,
|
|
229
|
+
`mssql://user:pass@host:1433/db`, `oracle://user:pass@host:1521/ORCL`.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Developer setup
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
git clone https://github.com/arunavdaniel/Autofeeder.git
|
|
237
|
+
cd Autofeeder
|
|
238
|
+
python -m venv .venv
|
|
239
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
240
|
+
pip install -e .
|
|
241
|
+
rss-text-reader # starts server + opens browser
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Build the frontend (only needed when editing frontend source):
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
cd frontend
|
|
248
|
+
npm install
|
|
249
|
+
npm run build # output goes to rss_reader/frontend_dist/
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Architecture
|
|
255
|
+
|
|
256
|
+
```mermaid
|
|
257
|
+
flowchart TB
|
|
258
|
+
subgraph Frontend["React 19 + Vite SPA (served from rss_reader/frontend_dist/)"]
|
|
259
|
+
UI["Overview · Sources · Discover · Websites · Schemas · Pipelines\nDuckDB · Embeddings · Semantic Search · Exports · Schedules · Run History · Stats · Settings"]
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
subgraph Backend["Flask backend (:8765)"]
|
|
263
|
+
Web["web.py — REST API + static SPA"]
|
|
264
|
+
Feeds["feeds.py — RSS/Atom + website fetch"]
|
|
265
|
+
Extract["extractor.py / llm.py — LLM JSON extraction"]
|
|
266
|
+
Pipe["pipeline.py — orchestration + scheduler"]
|
|
267
|
+
Duck["duckstore.py — DuckDB engine"]
|
|
268
|
+
Vec["vectorstore.py — local embeddings + cosine search"]
|
|
269
|
+
DB[("database.py — SQLite metadata")]
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
subgraph Storage["Local data (no cloud)"]
|
|
273
|
+
DDB[("DuckDB files (.duckdb)")]
|
|
274
|
+
SQL[("SQLite metadata DB")]
|
|
275
|
+
ART[("Article text snapshots")]
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
UI <-->|HTTP /api| Web
|
|
279
|
+
Web --> Feeds & Extract & Pipe & Duck & Vec & DB
|
|
280
|
+
Extract --> LLM["OpenAI-compatible LLM\n(Ollama / LM Studio / OpenAI / any)"]
|
|
281
|
+
Duck --> DDB
|
|
282
|
+
DB --> SQL
|
|
283
|
+
Feeds --> ART
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Project structure
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
Autofeeder/
|
|
292
|
+
├── rss_reader/ # Python backend (Flask)
|
|
293
|
+
│ ├── web.py # REST API + SPA serving
|
|
294
|
+
│ ├── database.py # SQLite metadata (feeds, schemas, pipelines, runs)
|
|
295
|
+
│ ├── duckstore.py # DuckDB engine (query, import, alter, export)
|
|
296
|
+
│ ├── extractor.py # extraction orchestration
|
|
297
|
+
│ ├── llm.py # OpenAI-compatible LLM client
|
|
298
|
+
│ ├── feeds.py # RSS/Atom fetch + parse
|
|
299
|
+
│ ├── fetchers.py # HTTP + Playwright fetcher abstraction
|
|
300
|
+
│ ├── pipeline.py # pipeline runner + scheduler loop
|
|
301
|
+
│ ├── chunker.py # paragraph/sentence chunking
|
|
302
|
+
│ ├── embeddings.py # embedding provider abstraction
|
|
303
|
+
│ ├── vectorstore.py # local cosine similarity search
|
|
304
|
+
│ ├── website.py # website monitor + change detection
|
|
305
|
+
│ ├── catalog.py # source catalog / discovery
|
|
306
|
+
│ ├── json_mapping.py # JSON/API extraction without LLM
|
|
307
|
+
│ ├── publish.py # RSS/JSON feed output
|
|
308
|
+
│ ├── backup.py # backup / restore
|
|
309
|
+
│ └── frontend_dist/ # pre-built React SPA (committed, ships with pip)
|
|
310
|
+
├── frontend/ # React 19 + Vite + TypeScript source
|
|
311
|
+
│ └── src/
|
|
312
|
+
│ ├── pages/ # one file per page/route
|
|
313
|
+
│ ├── components/ # ui primitives, layout, charts
|
|
314
|
+
│ └── lib/ # api.ts, types.ts, utils
|
|
315
|
+
├── install.py # cross-platform one-line installer
|
|
316
|
+
├── install.sh # macOS/Linux curl wrapper
|
|
317
|
+
├── install.ps1 # Windows PowerShell wrapper
|
|
318
|
+
├── packaging/ # PyInstaller spec (native app builds)
|
|
319
|
+
├── tests/
|
|
320
|
+
└── pyproject.toml
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Data location
|
|
326
|
+
|
|
327
|
+
| Platform | Path |
|
|
328
|
+
|---|---|
|
|
329
|
+
| macOS | `~/Library/Application Support/RSS Text Reader` |
|
|
330
|
+
| Windows | `%APPDATA%\RSS Text Reader` |
|
|
331
|
+
| Linux | `$XDG_DATA_HOME/RSS Text Reader` or `~/.local/share/RSS Text Reader` |
|
|
332
|
+
|
|
333
|
+
DuckDB files are stored in the **DuckDB viewer folder** you configure in the app. SQLite metadata and article snapshots go to the data location above.
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Autofeeder
|
|
2
|
+
|
|
3
|
+
> **Local-first intelligence extraction.** Point it at RSS feeds, websites, or APIs. Define what you want to pull out. Get a structured DuckDB table on your machine — no cloud, no accounts, no data leaving your box.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
One command. Opens in your browser when done. Works on macOS, Linux, and Windows — including locked-down enterprise machines.
|
|
10
|
+
|
|
11
|
+
### macOS / Linux
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
curl -fsSL https://raw.githubusercontent.com/arunavdaniel/Autofeeder/main/install.sh | sh
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Windows (PowerShell)
|
|
18
|
+
|
|
19
|
+
```powershell
|
|
20
|
+
iwr -useb https://raw.githubusercontent.com/arunavdaniel/Autofeeder/main/install.ps1 | iex
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### No `curl`? Any machine with Python works
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
python3 install.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> Download [`install.py`](https://raw.githubusercontent.com/arunavdaniel/Autofeeder/main/install.py) first, then run it. That's it.
|
|
30
|
+
|
|
31
|
+
After install, Autofeeder starts automatically and opens **http://127.0.0.1:8765** in your browser.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What it does
|
|
36
|
+
|
|
37
|
+
Autofeeder is an end-to-end extraction pipeline that runs entirely on your machine:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
SOURCES → FETCH → SNAPSHOT → TEXT EXTRACTION → LLM → DUCKDB
|
|
41
|
+
RSS HTTP/browser trafilatura any queryable
|
|
42
|
+
Atom or Playwright clean text OpenAI- structured
|
|
43
|
+
Websites compat table
|
|
44
|
+
APIs
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
1. **Subscribe to sources** — RSS/Atom feeds, arbitrary public websites, or JSON APIs. Group into folders.
|
|
48
|
+
2. **Snapshot** — Capture a reproducible point-in-time set of articles.
|
|
49
|
+
3. **Extract text** — Pull clean readable body text from raw HTML using trafilatura.
|
|
50
|
+
4. **Define a schema** — Describe what structured fields you want out of each article (name, type, description).
|
|
51
|
+
5. **Run LLM extraction** — Send article text + your prompt to any OpenAI-compatible model. Get validated JSON back.
|
|
52
|
+
6. **Write to DuckDB** — Records land in a local DuckDB table with metadata columns stamped automatically.
|
|
53
|
+
7. **Query** — Open the built-in SQL viewer, run any query, export to CSV/Parquet/JSON.
|
|
54
|
+
8. **Automate** — Schedule any pipeline on an interval or daily timer.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## What you can build with it
|
|
59
|
+
|
|
60
|
+
| Use case | What you do |
|
|
61
|
+
|---|---|
|
|
62
|
+
| **Market intelligence** | Subscribe to trade press, extract competitor pricing/announcements → queryable DuckDB table |
|
|
63
|
+
| **Research database** | Turn newsletters and blogs into structured facts you can `JOIN` and `GROUP BY` |
|
|
64
|
+
| **Knowledge base** | Feed a source list → chunk → embed → semantic search, all local |
|
|
65
|
+
| **Dataset creation** | Build schema-conforming labeled datasets for fine-tuning from web sources |
|
|
66
|
+
| **Website monitoring** | Watch public pages for meaningful changes, review diffs, trigger extraction on change |
|
|
67
|
+
| **Local LLM pipeline** | Point at Ollama or LM Studio — nothing leaves your machine, no API keys required |
|
|
68
|
+
| **Scheduled feeds** | Snapshot + schedule → rolling DuckDB table updated automatically on a timer |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Installer options
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Skip Playwright browser download (faster; JS-heavy article fetching unavailable)
|
|
76
|
+
python3 install.py --no-browser
|
|
77
|
+
|
|
78
|
+
# Custom install location
|
|
79
|
+
python3 install.py --dir /opt/autofeeder
|
|
80
|
+
|
|
81
|
+
# Install a specific version
|
|
82
|
+
python3 install.py --version 0.2.1
|
|
83
|
+
|
|
84
|
+
# Corporate SSL inspection / custom CA certificate
|
|
85
|
+
python3 install.py --ca-bundle /etc/ssl/corporate-ca.pem
|
|
86
|
+
|
|
87
|
+
# Fully offline / air-gapped — requires a pre-downloaded bundle zip
|
|
88
|
+
python3 install.py --offline --bundle ~/Downloads/autofeeder-bundle.zip
|
|
89
|
+
|
|
90
|
+
# Preview what would happen without making any changes
|
|
91
|
+
python3 install.py --dry-run
|
|
92
|
+
|
|
93
|
+
# Uninstall
|
|
94
|
+
python3 install.py --uninstall
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Enterprise compatibility
|
|
98
|
+
|
|
99
|
+
The installer works on locked-down machines with no admin rights:
|
|
100
|
+
|
|
101
|
+
| Restriction | How it's handled |
|
|
102
|
+
|---|---|
|
|
103
|
+
| No admin / sudo | Installs entirely to `~/.autofeeder/` in your home directory |
|
|
104
|
+
| No `git` | Downloads a source zip from GitHub releases or from PyPI |
|
|
105
|
+
| No `curl` / `wget` | Falls back to Python's built-in `urllib` automatically |
|
|
106
|
+
| Python < 3.10 or missing | Downloads a portable Python 3.12 via [python-build-standalone](https://github.com/indygreg/python-build-standalone) |
|
|
107
|
+
| HTTP/HTTPS proxy | Reads `HTTP_PROXY` / `HTTPS_PROXY` env vars |
|
|
108
|
+
| NTLM / Kerberos proxy (Windows) | `install.ps1` uses the system proxy with default network credentials |
|
|
109
|
+
| Corporate SSL inspection | `--ca-bundle` flag or `REQUESTS_CA_BUNDLE` env var |
|
|
110
|
+
| Playwright blocked by IT | `--no-browser` — app works fully without it |
|
|
111
|
+
| Air-gapped / no internet | `--offline --bundle` with a zip pre-downloaded on another machine |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Re-running after install
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
~/.autofeeder/autofeeder # macOS / Linux
|
|
119
|
+
~/.autofeeder/autofeeder.bat # Windows
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If Autofeeder is already running, the launcher detects it and just opens your browser to `http://127.0.0.1:8765` without starting a second instance.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Features
|
|
127
|
+
|
|
128
|
+
| Page | What you can do |
|
|
129
|
+
|---|---|
|
|
130
|
+
| **Overview** | Dashboard: counts of feeds, pipelines, runs, records extracted, errors. Last run summary. |
|
|
131
|
+
| **Sources** | Add/edit/delete RSS & Atom feeds. Group into folders. Auto-refresh every 15 m / 30 m / 1 h / 6 h. Optional Playwright browser fetch for JS-heavy sites. |
|
|
132
|
+
| **Discover** | Browse a curated catalog of feeds and websites to add in one click. |
|
|
133
|
+
| **Websites** | Monitor any public URL. HTTP or Playwright. Change detection via content hash. Diff review. Feed changes into pipelines. |
|
|
134
|
+
| **Schemas** | Define reusable extraction schemas: field name, type, description, required flag, default value. |
|
|
135
|
+
| **Pipelines** | Compose a run: source → LLM endpoint + model + prompt → schema → DuckDB output (append / overwrite / upsert, dedupe key). Preview one article before saving. Retries, concurrency, timeout. |
|
|
136
|
+
| **DuckDB** | SQL viewer: browse databases, open tables, run read-only or write queries, rename/delete databases and tables. |
|
|
137
|
+
| **Embeddings** | Chunk articles into paragraphs/sentences. Embed locally (deterministic hash vectors) or via any OpenAI-compatible endpoint, Ollama, or LM Studio. |
|
|
138
|
+
| **Semantic Search** | Embed a question → cosine similarity over local chunks → results with source, title, date, matched text, URL. |
|
|
139
|
+
| **Exports** | Export DuckDB tables or query results to CSV, Parquet, JSON, SQLite. Upsert-sync to Postgres, MySQL, MSSQL, Oracle. |
|
|
140
|
+
| **Schedules** | Create interval or daily snapshot schedules with a DuckDB destination. Runs automatically in the background. |
|
|
141
|
+
| **Run History** | Per-run logs, phase-by-phase progress, errors, and extracted output for every pipeline execution. |
|
|
142
|
+
| **Stats** | Charts of runs, records written, and errors over time. |
|
|
143
|
+
| **Settings** | Dark mode, app preferences. LLM API keys and endpoints stay in browser `localStorage` only — never written to the server. |
|
|
144
|
+
|
|
145
|
+
### Pipeline stages (only use what you need)
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
SOURCE → FETCH → SNAPSHOT → CHANGE DETECTION → TEXT EXTRACTION
|
|
149
|
+
↓
|
|
150
|
+
CHUNKING → EMBEDDING → LOCAL VECTOR SEARCH
|
|
151
|
+
↓
|
|
152
|
+
LLM EXTRACTION → VALIDATION → DEDUPLICATION
|
|
153
|
+
↓
|
|
154
|
+
DUCKDB → EXPORT / REPLICATION
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### DuckDB output schema
|
|
158
|
+
|
|
159
|
+
Every extracted record carries automatic metadata columns:
|
|
160
|
+
|
|
161
|
+
```sql
|
|
162
|
+
ingested_at TIMESTAMP -- when the record was written
|
|
163
|
+
feed_title VARCHAR -- source feed or website name
|
|
164
|
+
article_url VARCHAR -- original article URL
|
|
165
|
+
run_id BIGINT -- links back to the pipeline run
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Privacy
|
|
169
|
+
|
|
170
|
+
- LLM API keys are used for the outbound request only. They are **never written to disk or the local database**.
|
|
171
|
+
- Endpoint, model, and prompt live in browser `localStorage`.
|
|
172
|
+
- No telemetry. No accounts. No network calls except to feeds and the LLM endpoint you configure.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## LLM configuration
|
|
177
|
+
|
|
178
|
+
Autofeeder works with any OpenAI-compatible chat completions endpoint:
|
|
179
|
+
|
|
180
|
+
| Provider | Endpoint |
|
|
181
|
+
|---|---|
|
|
182
|
+
| OpenAI | `https://api.openai.com/v1/chat/completions` |
|
|
183
|
+
| Ollama (local) | `http://localhost:11434/v1/chat/completions` |
|
|
184
|
+
| LM Studio (local) | `http://localhost:1234/v1/chat/completions` |
|
|
185
|
+
| Anything else | Any `POST /v1/chat/completions` compatible API |
|
|
186
|
+
|
|
187
|
+
Configure in **Settings → LLM**. The key is used only for the duration of the request.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Optional extras
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Playwright browser (for JS-heavy article fetching)
|
|
195
|
+
pip install 'autofeeder[browser]'
|
|
196
|
+
python -m playwright install chromium
|
|
197
|
+
|
|
198
|
+
# Database sync / upsert (Postgres, MySQL, MSSQL, Oracle)
|
|
199
|
+
pip install 'autofeeder[sync]'
|
|
200
|
+
|
|
201
|
+
# Sentence-level embeddings via sentence-transformers
|
|
202
|
+
pip install 'autofeeder[embeddings]'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Connection strings: `postgres://user:pass@host:5432/db`, `mysql://user:pass@host:3306/db`,
|
|
206
|
+
`mssql://user:pass@host:1433/db`, `oracle://user:pass@host:1521/ORCL`.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Developer setup
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
git clone https://github.com/arunavdaniel/Autofeeder.git
|
|
214
|
+
cd Autofeeder
|
|
215
|
+
python -m venv .venv
|
|
216
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
217
|
+
pip install -e .
|
|
218
|
+
rss-text-reader # starts server + opens browser
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Build the frontend (only needed when editing frontend source):
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
cd frontend
|
|
225
|
+
npm install
|
|
226
|
+
npm run build # output goes to rss_reader/frontend_dist/
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Architecture
|
|
232
|
+
|
|
233
|
+
```mermaid
|
|
234
|
+
flowchart TB
|
|
235
|
+
subgraph Frontend["React 19 + Vite SPA (served from rss_reader/frontend_dist/)"]
|
|
236
|
+
UI["Overview · Sources · Discover · Websites · Schemas · Pipelines\nDuckDB · Embeddings · Semantic Search · Exports · Schedules · Run History · Stats · Settings"]
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
subgraph Backend["Flask backend (:8765)"]
|
|
240
|
+
Web["web.py — REST API + static SPA"]
|
|
241
|
+
Feeds["feeds.py — RSS/Atom + website fetch"]
|
|
242
|
+
Extract["extractor.py / llm.py — LLM JSON extraction"]
|
|
243
|
+
Pipe["pipeline.py — orchestration + scheduler"]
|
|
244
|
+
Duck["duckstore.py — DuckDB engine"]
|
|
245
|
+
Vec["vectorstore.py — local embeddings + cosine search"]
|
|
246
|
+
DB[("database.py — SQLite metadata")]
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
subgraph Storage["Local data (no cloud)"]
|
|
250
|
+
DDB[("DuckDB files (.duckdb)")]
|
|
251
|
+
SQL[("SQLite metadata DB")]
|
|
252
|
+
ART[("Article text snapshots")]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
UI <-->|HTTP /api| Web
|
|
256
|
+
Web --> Feeds & Extract & Pipe & Duck & Vec & DB
|
|
257
|
+
Extract --> LLM["OpenAI-compatible LLM\n(Ollama / LM Studio / OpenAI / any)"]
|
|
258
|
+
Duck --> DDB
|
|
259
|
+
DB --> SQL
|
|
260
|
+
Feeds --> ART
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Project structure
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
Autofeeder/
|
|
269
|
+
├── rss_reader/ # Python backend (Flask)
|
|
270
|
+
│ ├── web.py # REST API + SPA serving
|
|
271
|
+
│ ├── database.py # SQLite metadata (feeds, schemas, pipelines, runs)
|
|
272
|
+
│ ├── duckstore.py # DuckDB engine (query, import, alter, export)
|
|
273
|
+
│ ├── extractor.py # extraction orchestration
|
|
274
|
+
│ ├── llm.py # OpenAI-compatible LLM client
|
|
275
|
+
│ ├── feeds.py # RSS/Atom fetch + parse
|
|
276
|
+
│ ├── fetchers.py # HTTP + Playwright fetcher abstraction
|
|
277
|
+
│ ├── pipeline.py # pipeline runner + scheduler loop
|
|
278
|
+
│ ├── chunker.py # paragraph/sentence chunking
|
|
279
|
+
│ ├── embeddings.py # embedding provider abstraction
|
|
280
|
+
│ ├── vectorstore.py # local cosine similarity search
|
|
281
|
+
│ ├── website.py # website monitor + change detection
|
|
282
|
+
│ ├── catalog.py # source catalog / discovery
|
|
283
|
+
│ ├── json_mapping.py # JSON/API extraction without LLM
|
|
284
|
+
│ ├── publish.py # RSS/JSON feed output
|
|
285
|
+
│ ├── backup.py # backup / restore
|
|
286
|
+
│ └── frontend_dist/ # pre-built React SPA (committed, ships with pip)
|
|
287
|
+
├── frontend/ # React 19 + Vite + TypeScript source
|
|
288
|
+
│ └── src/
|
|
289
|
+
│ ├── pages/ # one file per page/route
|
|
290
|
+
│ ├── components/ # ui primitives, layout, charts
|
|
291
|
+
│ └── lib/ # api.ts, types.ts, utils
|
|
292
|
+
├── install.py # cross-platform one-line installer
|
|
293
|
+
├── install.sh # macOS/Linux curl wrapper
|
|
294
|
+
├── install.ps1 # Windows PowerShell wrapper
|
|
295
|
+
├── packaging/ # PyInstaller spec (native app builds)
|
|
296
|
+
├── tests/
|
|
297
|
+
└── pyproject.toml
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Data location
|
|
303
|
+
|
|
304
|
+
| Platform | Path |
|
|
305
|
+
|---|---|
|
|
306
|
+
| macOS | `~/Library/Application Support/RSS Text Reader` |
|
|
307
|
+
| Windows | `%APPDATA%\RSS Text Reader` |
|
|
308
|
+
| Linux | `$XDG_DATA_HOME/RSS Text Reader` or `~/.local/share/RSS Text Reader` |
|
|
309
|
+
|
|
310
|
+
DuckDB files are stored in the **DuckDB viewer folder** you configure in the app. SQLite metadata and article snapshots go to the data location above.
|