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.
Files changed (51) hide show
  1. autofeeder-0.1.1/PKG-INFO +333 -0
  2. autofeeder-0.1.1/README.md +310 -0
  3. autofeeder-0.1.1/autofeeder.egg-info/PKG-INFO +333 -0
  4. autofeeder-0.1.1/autofeeder.egg-info/SOURCES.txt +49 -0
  5. autofeeder-0.1.1/autofeeder.egg-info/dependency_links.txt +1 -0
  6. autofeeder-0.1.1/autofeeder.egg-info/entry_points.txt +2 -0
  7. autofeeder-0.1.1/autofeeder.egg-info/requires.txt +19 -0
  8. autofeeder-0.1.1/autofeeder.egg-info/top_level.txt +1 -0
  9. autofeeder-0.1.1/pyproject.toml +46 -0
  10. autofeeder-0.1.1/rss_reader/__init__.py +1 -0
  11. autofeeder-0.1.1/rss_reader/app.py +322 -0
  12. autofeeder-0.1.1/rss_reader/backup.py +80 -0
  13. autofeeder-0.1.1/rss_reader/catalog.py +234 -0
  14. autofeeder-0.1.1/rss_reader/catalog_providers.py +459 -0
  15. autofeeder-0.1.1/rss_reader/chunker.py +29 -0
  16. autofeeder-0.1.1/rss_reader/data/catalog_snapshots/apis.json +1 -0
  17. autofeeder-0.1.1/rss_reader/data/catalog_snapshots/feeds.json +1 -0
  18. autofeeder-0.1.1/rss_reader/data/catalog_snapshots/websites.json +1 -0
  19. autofeeder-0.1.1/rss_reader/data/source_catalog.json +71 -0
  20. autofeeder-0.1.1/rss_reader/database.py +1624 -0
  21. autofeeder-0.1.1/rss_reader/duckstore.py +846 -0
  22. autofeeder-0.1.1/rss_reader/embeddings.py +229 -0
  23. autofeeder-0.1.1/rss_reader/extractor.py +166 -0
  24. autofeeder-0.1.1/rss_reader/feeds.py +123 -0
  25. autofeeder-0.1.1/rss_reader/fetchers.py +445 -0
  26. autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  27. autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  28. autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  29. autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  30. autofeeder-0.1.1/rss_reader/frontend_dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  31. autofeeder-0.1.1/rss_reader/frontend_dist/assets/index-C91Lco4U.js +13 -0
  32. autofeeder-0.1.1/rss_reader/frontend_dist/assets/index-CuFzDjkd.css +1 -0
  33. autofeeder-0.1.1/rss_reader/frontend_dist/favicon.svg +9 -0
  34. autofeeder-0.1.1/rss_reader/frontend_dist/icons.svg +24 -0
  35. autofeeder-0.1.1/rss_reader/frontend_dist/index.html +23 -0
  36. autofeeder-0.1.1/rss_reader/json_mapping.py +64 -0
  37. autofeeder-0.1.1/rss_reader/llm.py +81 -0
  38. autofeeder-0.1.1/rss_reader/pipeline.py +1309 -0
  39. autofeeder-0.1.1/rss_reader/publish.py +386 -0
  40. autofeeder-0.1.1/rss_reader/session_store.py +87 -0
  41. autofeeder-0.1.1/rss_reader/vectorstore.py +115 -0
  42. autofeeder-0.1.1/rss_reader/web.py +2309 -0
  43. autofeeder-0.1.1/rss_reader/website.py +427 -0
  44. autofeeder-0.1.1/setup.cfg +4 -0
  45. autofeeder-0.1.1/tests/test_catalog.py +185 -0
  46. autofeeder-0.1.1/tests/test_core.py +77 -0
  47. autofeeder-0.1.1/tests/test_extraction_features.py +466 -0
  48. autofeeder-0.1.1/tests/test_llm.py +30 -0
  49. autofeeder-0.1.1/tests/test_pipeline.py +282 -0
  50. autofeeder-0.1.1/tests/test_production.py +74 -0
  51. 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.