stock-weekly-report 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # stock-weekly-report
2
+
3
+ By [Chang Yu Chuan](https://github.com/ChangYuChuan)
4
+
5
+ Automated pipeline that fetches Taiwanese stock podcast episodes, transcribes them with Whisper, uploads to NotebookLM, and emails a structured weekly investment report.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ### Via npm (recommended)
12
+
13
+ ```bash
14
+ npm install -g stock-weekly-report
15
+ ```
16
+
17
+ `postinstall` automatically finds Python 3.10+ on your system and creates the `venv14/` environment. After that, `swr` and `swr-mcp` are available globally.
18
+
19
+ Then set up the pipeline venv (needed for actual transcription runs):
20
+
21
+ ```bash
22
+ cd $(npm root -g)/stock-weekly-report
23
+ python3 -m venv venv && venv/bin/pip install -r requirements.txt
24
+ ```
25
+
26
+ Finally run the setup wizard:
27
+ ```bash
28
+ swr init
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Manual Setup
34
+
35
+ ### 1. Prerequisites
36
+
37
+ - Python 3.9+ (pipeline) and Python 3.10+ (CLI/MCP — Homebrew `python3.14` recommended)
38
+ - [nlm](https://github.com/OpenClaw-AI/notebooklm-mcp-cli) binary (`~/.openclaw/workspace/venv/bin/nlm`)
39
+ - Gmail account with an [App Password](https://support.google.com/accounts/answer/185833)
40
+
41
+ ### 2. Pipeline venv (Python 3.9)
42
+
43
+ ```bash
44
+ python3 -m venv venv
45
+ venv/bin/pip install -r requirements.txt
46
+ ```
47
+
48
+ ### 3. CLI + MCP venv (Python 3.10+)
49
+
50
+ ```bash
51
+ /opt/homebrew/bin/python3.14 -m venv venv14
52
+ venv14/bin/pip install -e .
53
+ ```
54
+
55
+ This installs two entry points:
56
+ - `venv14/bin/swr` — the CLI
57
+ - `venv14/bin/swr-mcp` — the MCP server
58
+
59
+ Optionally add `venv14/bin` to your `PATH`:
60
+ ```bash
61
+ echo 'export PATH="/path/to/stock-weekly-report/venv14/bin:$PATH"' >> ~/.zprofile
62
+ ```
63
+
64
+ ### 4. First-time configuration
65
+
66
+ ```bash
67
+ swr init
68
+ ```
69
+
70
+ The wizard prompts for data folder, nlm path, Gmail app password, sender/recipient emails, and retention periods. It writes `config.yaml` (git-ignored) and optionally installs the cron job.
71
+
72
+ To start from a template instead:
73
+ ```bash
74
+ cp config.yaml.example config.yaml
75
+ # edit config.yaml, then export EMAIL_SMTP_PASSWORD in ~/.zprofile
76
+ ```
77
+
78
+ ---
79
+
80
+ ## CLI reference
81
+
82
+ ```
83
+ swr [--config PATH]
84
+ ├── init Interactive setup wizard
85
+ ├── run Run the pipeline
86
+ │ --skip-fetch Skip podcast download
87
+ │ --skip-transcribe Skip Whisper transcription
88
+ │ --skip-upload Skip NotebookLM upload
89
+ │ --skip-email Skip report generation entirely
90
+ │ --skip-cleanup Skip data cleanup
91
+ │ --save-report-only Generate report but don't send email
92
+ │ --folder FOLDER e.g. 20260218-20260225
93
+ │ --notebook-id ID Reuse an existing notebook (skips upload)
94
+
95
+ ├── podcast
96
+ │ ├── list List configured feeds
97
+ │ ├── add NAME URL Add a feed
98
+ │ └── remove NAME Remove a feed
99
+
100
+ ├── receiver
101
+ │ ├── list List configured recipients
102
+ │ ├── add EMAIL Add a recipient
103
+ │ └── remove EMAIL Remove a recipient
104
+
105
+ ├── cron
106
+ │ ├── install [--schedule EXPR] Install (or update) the cron job
107
+ │ ├── remove Remove the cron job
108
+ │ └── status Show cron job status
109
+
110
+ ├── config
111
+ │ ├── show Display current config (passwords redacted)
112
+ │ └── set KEY VALUE Set a value (e.g. retention.audio_months 6)
113
+
114
+ └── mcp Start the MCP server (stdio transport)
115
+ ```
116
+
117
+ ### Common examples
118
+
119
+ ```bash
120
+ # Full pipeline run
121
+ swr run
122
+
123
+ # Skip fetch + transcribe, reuse existing notebook, only send email
124
+ swr run --skip-fetch --skip-transcribe --notebook-id e08a19e4-b8b7-48dc-88d6-2f2393239c36
125
+
126
+ # Generate and save report locally without sending email
127
+ swr run --skip-fetch --skip-transcribe --notebook-id <id> --save-report-only
128
+
129
+ # Manage feeds
130
+ swr podcast list
131
+ swr podcast add "新節目" https://example.com/feed.xml
132
+ swr podcast remove "新節目"
133
+
134
+ # Manage recipients
135
+ swr receiver list
136
+ swr receiver add colleague@example.com
137
+ swr receiver remove colleague@example.com
138
+
139
+ # Cron job — install on Sundays at 8 AM
140
+ swr cron install
141
+ swr cron install --schedule "0 9 * * 0" # Sundays at 9 AM
142
+ swr cron status
143
+ swr cron remove
144
+
145
+ # Config
146
+ swr config show
147
+ swr config set retention.audio_months 6
148
+ swr config set retention.transcripts_months 3
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Retention
154
+
155
+ By default, audio files older than 3 months are deleted. Transcripts and reports are kept forever. Adjust in config:
156
+
157
+ ```yaml
158
+ retention:
159
+ audio_months: 3 # 0 = keep forever
160
+ transcripts_months: 6 # 0 = keep forever
161
+ reports_months: 12 # 0 = keep forever
162
+ ```
163
+
164
+ Or via CLI:
165
+ ```bash
166
+ swr config set retention.audio_months 6
167
+ ```
168
+
169
+ ---
170
+
171
+ ## MCP server
172
+
173
+ The MCP server exposes four tools for use with Claude Desktop or any MCP client:
174
+
175
+ | Tool | Description |
176
+ |---|---|
177
+ | `run_pipeline` | Run the pipeline (with stage selection, save-only mode) |
178
+ | `get_report` | Read a saved report (defaults to latest) |
179
+ | `list_reports` | List all available report folders |
180
+ | `get_logs` | Tail the pipeline log |
181
+
182
+ ### Claude Desktop integration
183
+
184
+ If installed via npm:
185
+ ```json
186
+ {
187
+ "mcpServers": {
188
+ "stock-weekly-report": {
189
+ "command": "swr-mcp"
190
+ }
191
+ }
192
+ }
193
+ ```
194
+
195
+ If installed manually:
196
+ ```json
197
+ {
198
+ "mcpServers": {
199
+ "stock-weekly-report": {
200
+ "command": "/Users/yuchuan/Projects/stock-weekly-report/venv14/bin/swr-mcp"
201
+ }
202
+ }
203
+ }
204
+ ```
205
+
206
+ Start the server manually for testing:
207
+ ```bash
208
+ swr mcp
209
+ # or
210
+ venv14/bin/swr-mcp
211
+ ```
212
+
213
+ ---
214
+
215
+ ## Cron job
216
+
217
+ The cron job calls `run.sh`, which sources `~/.zprofile` (for `EMAIL_SMTP_PASSWORD`) and logs output to `logs/pipeline.log`.
218
+
219
+ ```bash
220
+ swr cron install # Sundays at 8 AM (default)
221
+ swr cron install --schedule "0 9 * * 0" # Sundays at 9 AM
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Project structure
227
+
228
+ ```
229
+ stock-weekly-report/
230
+ ├── pipeline.py # Orchestrates all stages
231
+ ├── fetch_episodes.py # Stage 1: download podcast episodes
232
+ ├── transcribe.py # Stage 2: Whisper transcription
233
+ ├── upload_to_notebooklm.py # Stage 3: NotebookLM upload
234
+ ├── send_report.py # Stage 4: report generation + email
235
+ ├── cli.py # swr CLI (click)
236
+ ├── mcp_server.py # MCP server (FastMCP)
237
+ ├── config_manager.py # Atomic config read/write helper
238
+ ├── run.sh # Shell wrapper (sources ~/.zprofile, logs to file)
239
+ ├── config.yaml # Your config (git-ignored, create with `swr init`)
240
+ ├── config.yaml.example # Template
241
+ ├── pyproject.toml # Entry point declarations
242
+ ├── requirements.txt # Pipeline dependencies
243
+ ├── venv/ # Python 3.9 venv (pipeline + transcription)
244
+ └── venv14/ # Python 3.14 venv (CLI + MCP server)
245
+ ```
package/bin/swr-mcp.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawn } = require("child_process");
5
+ const path = require("path");
6
+
7
+ const bin = path.join(__dirname, "..", "venv14", "bin", "swr-mcp");
8
+ const proc = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
9
+ proc.on("close", (code) => process.exit(code ?? 0));
package/bin/swr.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawn } = require("child_process");
5
+ const path = require("path");
6
+
7
+ const bin = path.join(__dirname, "..", "venv14", "bin", "swr");
8
+ const proc = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
9
+ proc.on("close", (code) => process.exit(code ?? 0));