aether-mkt 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.
- aether_mkt-0.1.1/.env.example +40 -0
- aether_mkt-0.1.1/.gitignore +43 -0
- aether_mkt-0.1.1/AGENTS.md +132 -0
- aether_mkt-0.1.1/CLAUDE.md +52 -0
- aether_mkt-0.1.1/PKG-INFO +92 -0
- aether_mkt-0.1.1/README.md +64 -0
- aether_mkt-0.1.1/aether/__init__.py +12 -0
- aether_mkt-0.1.1/aether/cli.py +562 -0
- aether_mkt-0.1.1/aether/deploy/com.aether.web.plist +81 -0
- aether_mkt-0.1.1/aether/deploy/db/schema.sql +155 -0
- aether_mkt-0.1.1/blocks/README.md +103 -0
- aether_mkt-0.1.1/blocks/__init__.py +2 -0
- aether_mkt-0.1.1/blocks/_templates/README.md +14 -0
- aether_mkt-0.1.1/blocks/publish/README.md +28 -0
- aether_mkt-0.1.1/blocks/publish/__init__.py +2 -0
- aether_mkt-0.1.1/blocks/rewrite/README.md +25 -0
- aether_mkt-0.1.1/blocks/rewrite/__init__.py +3 -0
- aether_mkt-0.1.1/blocks/rewrite/platform_creator.py +307 -0
- aether_mkt-0.1.1/blocks/rewrite/state.py +30 -0
- aether_mkt-0.1.1/blocks/rewrite/tests/__init__.py +0 -0
- aether_mkt-0.1.1/blocks/rewrite/tests/test_rewrite.py +300 -0
- aether_mkt-0.1.1/blocks/rewrite/translation_launcher.py +397 -0
- aether_mkt-0.1.1/blocks/rewrite/wechat/README.md +137 -0
- aether_mkt-0.1.1/blocks/rewrite/wechat/__init__.py +3 -0
- aether_mkt-0.1.1/blocks/rewrite/wechat/expected/README.md +35 -0
- aether_mkt-0.1.1/blocks/rewrite/wechat/prompt.v1.md +137 -0
- aether_mkt-0.1.1/blocks/rewrite/wechat/samples/README.md +31 -0
- aether_mkt-0.1.1/blocks/rewrite/xiaohongshu/__init__.py +2 -0
- aether_mkt-0.1.1/blocks/rewrite/xiaohongshu/prompt.v1.md +142 -0
- aether_mkt-0.1.1/blocks/sources/README.md +22 -0
- aether_mkt-0.1.1/blocks/sources/__init__.py +2 -0
- aether_mkt-0.1.1/blocks/sources/basic/README.md +98 -0
- aether_mkt-0.1.1/blocks/sources/basic/__init__.py +1 -0
- aether_mkt-0.1.1/blocks/sources/basic/parser.py +125 -0
- aether_mkt-0.1.1/blocks/sources/basic/sources.yaml +103 -0
- aether_mkt-0.1.1/blocks/sources/basic/state.py +33 -0
- aether_mkt-0.1.1/blocks/sources/basic/subgraph.py +162 -0
- aether_mkt-0.1.1/blocks/sources/basic/tests/__init__.py +1 -0
- aether_mkt-0.1.1/blocks/sources/basic/tests/test_subgraph.py +67 -0
- aether_mkt-0.1.1/blocks/sources/multi/__init__.py +7 -0
- aether_mkt-0.1.1/blocks/sources/multi/__main__.py +7 -0
- aether_mkt-0.1.1/blocks/sources/multi/content_fetch.py +408 -0
- aether_mkt-0.1.1/blocks/sources/multi/strategies/__init__.py +41 -0
- aether_mkt-0.1.1/blocks/sources/multi/strategies/contentmarketinginstitute.py +103 -0
- aether_mkt-0.1.1/blocks/sources/multi/strategies/searchengineland.py +25 -0
- aether_mkt-0.1.1/blocks/sources/multi/strategies/socialmediaexaminer.py +25 -0
- aether_mkt-0.1.1/blocks/sources/multi/strategies/wordstream.py +20 -0
- aether_mkt-0.1.1/blocks/sources/multi/subgraph.py +363 -0
- aether_mkt-0.1.1/blocks/sources/multi/tests/__init__.py +0 -0
- aether_mkt-0.1.1/blocks/sources/multi/tests/test_content_fetch.py +398 -0
- aether_mkt-0.1.1/blocks/sources/multi/tests/test_subgraph_filter.py +167 -0
- aether_mkt-0.1.1/blocks/sources/multi/tests/walkthrough.py +359 -0
- aether_mkt-0.1.1/blocks/sources/scheduler/__init__.py +1 -0
- aether_mkt-0.1.1/data/.gitkeep +1 -0
- aether_mkt-0.1.1/db/README.md +275 -0
- aether_mkt-0.1.1/db/__init__.py +1 -0
- aether_mkt-0.1.1/db/agent_descriptors/source_getter.contentmarketinginstitute.json +43 -0
- aether_mkt-0.1.1/db/agent_descriptors/source_getter.hubspot.json +17 -0
- aether_mkt-0.1.1/db/agent_descriptors/source_getter.searchengineland.json +24 -0
- aether_mkt-0.1.1/db/agent_descriptors/source_getter.socialmediaexaminer.json +24 -0
- aether_mkt-0.1.1/db/agent_descriptors/source_getter.wordstream.json +24 -0
- aether_mkt-0.1.1/db/agent_factory.py +444 -0
- aether_mkt-0.1.1/db/schema.sql +155 -0
- aether_mkt-0.1.1/db/seed_agent_factory.py +73 -0
- aether_mkt-0.1.1/db/seed_sources.py +99 -0
- aether_mkt-0.1.1/db/sources.py +529 -0
- aether_mkt-0.1.1/docker-compose.yml +30 -0
- aether_mkt-0.1.1/docs/architecture.html +1030 -0
- aether_mkt-0.1.1/docs/decisions/0001-three-stage-architecture.md +46 -0
- aether_mkt-0.1.1/docs/decisions/0002-block-by-block-validation.md +53 -0
- aether_mkt-0.1.1/docs/decisions/0003-block-0-source-first-langgraph-day-1.md +53 -0
- aether_mkt-0.1.1/docs/decisions/0004-postgres-as-state-store.md +98 -0
- aether_mkt-0.1.1/docs/decisions/0005-llm-provider-abstraction.md +110 -0
- aether_mkt-0.1.1/docs/decisions/0006-src-and-stage-nested-blocks.md +144 -0
- aether_mkt-0.1.1/docs/decisions/0007-v0-1-drop-and-recreate-schema.md +77 -0
- aether_mkt-0.1.1/docs/decisions/README.md +44 -0
- aether_mkt-0.1.1/docs/design.md +310 -0
- aether_mkt-0.1.1/docs/install-mac.md +148 -0
- aether_mkt-0.1.1/docs/roadmap.md +186 -0
- aether_mkt-0.1.1/docs/tech-stack.md +107 -0
- aether_mkt-0.1.1/logs/2026-06-30-block-00-judgment.md +54 -0
- aether_mkt-0.1.1/logs/2026-06-30-block-01-judgment.md +106 -0
- aether_mkt-0.1.1/logs/2026-06-30-block-01b-judgment.md +126 -0
- aether_mkt-0.1.1/logs/2026-06-30-block-01c-judgment.md +163 -0
- aether_mkt-0.1.1/logs/2026-06-30-wrap-up.md +121 -0
- aether_mkt-0.1.1/logs/2026-07-01-block-01d-judgment.md +224 -0
- aether_mkt-0.1.1/logs/2026-07-01-block-03-judgment.md +257 -0
- aether_mkt-0.1.1/logs/2026-07-01-web-mvp-judgment.md +236 -0
- aether_mkt-0.1.1/logs/README.md +35 -0
- aether_mkt-0.1.1/logs/template.md +46 -0
- aether_mkt-0.1.1/pyproject.toml +75 -0
- aether_mkt-0.1.1/scripts/README.md +13 -0
- aether_mkt-0.1.1/scripts/publish-pypi.sh +56 -0
- aether_mkt-0.1.1/src/__init__.py +107 -0
- aether_mkt-0.1.1/src/base_subgraph.py +109 -0
- aether_mkt-0.1.1/src/browser.py +84 -0
- aether_mkt-0.1.1/src/config.py +258 -0
- aether_mkt-0.1.1/src/db.py +394 -0
- aether_mkt-0.1.1/src/extractor.py +473 -0
- aether_mkt-0.1.1/src/fetcher.py +36 -0
- aether_mkt-0.1.1/src/image_handler.py +147 -0
- aether_mkt-0.1.1/src/llm.py +299 -0
- aether_mkt-0.1.1/src/parsers.py +275 -0
- aether_mkt-0.1.1/src/registry.py +204 -0
- aether_mkt-0.1.1/src/single_getter.py +61 -0
- aether_mkt-0.1.1/src/strategies.py +109 -0
- aether_mkt-0.1.1/tests/README.md +24 -0
- aether_mkt-0.1.1/tests/__init__.py +1 -0
- aether_mkt-0.1.1/tests/conftest.py +10 -0
- aether_mkt-0.1.1/tests/test_agent_factory.py +244 -0
- aether_mkt-0.1.1/tests/test_cli.py +360 -0
- aether_mkt-0.1.1/tests/test_db_upsert_draft.py +156 -0
- aether_mkt-0.1.1/tests/test_extractor.py +382 -0
- aether_mkt-0.1.1/tests/test_image_handler.py +108 -0
- aether_mkt-0.1.1/tests/test_llm.py +232 -0
- aether_mkt-0.1.1/tests/test_sources_api.py +420 -0
- aether_mkt-0.1.1/uv.lock +2159 -0
- aether_mkt-0.1.1/web/README.md +175 -0
- aether_mkt-0.1.1/web/__init__.py +2 -0
- aether_mkt-0.1.1/web/app.py +88 -0
- aether_mkt-0.1.1/web/queries.py +277 -0
- aether_mkt-0.1.1/web/routes/__init__.py +1 -0
- aether_mkt-0.1.1/web/routes/actions.py +164 -0
- aether_mkt-0.1.1/web/routes/articles.py +87 -0
- aether_mkt-0.1.1/web/routes/drafts.py +52 -0
- aether_mkt-0.1.1/web/routes/placeholders.py +48 -0
- aether_mkt-0.1.1/web/routes/settings.py +157 -0
- aether_mkt-0.1.1/web/routes/sources.py +57 -0
- aether_mkt-0.1.1/web/settings_store.py +90 -0
- aether_mkt-0.1.1/web/static/style.css +418 -0
- aether_mkt-0.1.1/web/templates/articles/list.html +96 -0
- aether_mkt-0.1.1/web/templates/articles/translate.html +91 -0
- aether_mkt-0.1.1/web/templates/base.html +43 -0
- aether_mkt-0.1.1/web/templates/drafts/detail.html +76 -0
- aether_mkt-0.1.1/web/templates/drafts/list.html +90 -0
- aether_mkt-0.1.1/web/templates/placeholders/coming_soon.html +16 -0
- aether_mkt-0.1.1/web/templates/settings/edit.html +118 -0
- aether_mkt-0.1.1/web/templates/sources/fetch.html +114 -0
- aether_mkt-0.1.1/web/templates/sources/list.html +77 -0
- aether_mkt-0.1.1/web/tests/__init__.py +1 -0
- aether_mkt-0.1.1/web/tests/test_app.py +341 -0
- aether_mkt-0.1.1/web/tests/test_settings.py +289 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Real env vars for aether v0.1
|
|
2
|
+
# Copy this file to .env and fill in real values.
|
|
3
|
+
|
|
4
|
+
# ===== DB (Postgres) =====
|
|
5
|
+
DATABASE_URL=postgresql://aether:aether@localhost:5432/aether
|
|
6
|
+
|
|
7
|
+
# ===== LLM Provider(直连 + OpenRouter 双轨,三件套切模型只改 env 不改代码)=====
|
|
8
|
+
# 推荐先用 OpenRouter:一个 key 全能切换 Claude / DeepSeek / MiMo / 其他
|
|
9
|
+
# OpenAI/Anthropic 兼容 endpoint 都行 —— 切 provider 改 3 行。
|
|
10
|
+
|
|
11
|
+
# 默认:直连 Anthropic
|
|
12
|
+
LLM_BASE_URL=https://api.anthropic.com
|
|
13
|
+
LLM_MODEL=claude-sonnet-4-6
|
|
14
|
+
LLM_API_KEY=sk-ant-REPLACE_BEFORE_BLOCK_3
|
|
15
|
+
|
|
16
|
+
# --- 其他 provider 选项(任一行取消注释填值即可) ---
|
|
17
|
+
# OpenRouter(一个 key 路由到任意模型):
|
|
18
|
+
# LLM_BASE_URL=https://openrouter.ai/api/v1
|
|
19
|
+
# LLM_MODEL=deepseek/deepseek-v4-flash ← 或 anthropic/claude-sonnet-4-6 / 任意
|
|
20
|
+
# LLM_API_KEY=sk-or-xxxxx
|
|
21
|
+
#
|
|
22
|
+
# DeepSeek V4-Flash 直连(最便宜):
|
|
23
|
+
# LLM_BASE_URL=https://api.deepseek.com/anthropic
|
|
24
|
+
# LLM_MODEL=deepseek-chat
|
|
25
|
+
# LLM_API_KEY=sk-xxxxx
|
|
26
|
+
#
|
|
27
|
+
# 小米 MiMo V2.5-Flash 直连:
|
|
28
|
+
# LLM_BASE_URL=https://api.xiaomimimo.com/anthropic
|
|
29
|
+
# LLM_MODEL=mimo-v2-flash
|
|
30
|
+
# LLM_API_KEY=xxxxx
|
|
31
|
+
|
|
32
|
+
# ===== LangSmith(Block 5+ 可观测,可选)=====
|
|
33
|
+
# LANGCHAIN_TRACING_V2=true
|
|
34
|
+
# LANGCHAIN_API_KEY=lsv2-xxxxx
|
|
35
|
+
# LANGCHAIN_PROJECT=aether-v0.1
|
|
36
|
+
|
|
37
|
+
# ===== 数据源抓取层(Block 0)=====
|
|
38
|
+
USER_AGENT=AetherBot/0.1
|
|
39
|
+
REQUEST_TIMEOUT=30
|
|
40
|
+
DEFAULT_TOP_N=3
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
|
|
12
|
+
# Node
|
|
13
|
+
node_modules/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
.next/
|
|
17
|
+
|
|
18
|
+
# Secrets & local config
|
|
19
|
+
.env
|
|
20
|
+
.env.local
|
|
21
|
+
*.local
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
*.swp
|
|
27
|
+
|
|
28
|
+
# Block run artefacts (raw; curated runs go in expected/)
|
|
29
|
+
# Inline gitignores in each blocks/NN-name/runs/ handle the file-level rules.
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
desktop.ini
|
|
35
|
+
|
|
36
|
+
# Downloads
|
|
37
|
+
downloads/
|
|
38
|
+
|
|
39
|
+
# Block 3B: image_handler downloads (rewritten articles' images go here)
|
|
40
|
+
data/article_images/
|
|
41
|
+
# Web control panel: runtime settings overrides (UI 改 LLM key 等不进 git)
|
|
42
|
+
data/*.json
|
|
43
|
+
!data/.gitkeep
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
内容分发工作流 · v0.1 MVP 验证项目。**任何 AI 编码工具读我之前,先读这四份**:
|
|
4
|
+
|
|
5
|
+
1. `README.md` — 项目是什么、为什么
|
|
6
|
+
2. `docs/roadmap.md` — 目前在哪个块,前面通过了哪些
|
|
7
|
+
3. 当前活跃的 `blocks/<stage>/<block>/README.md` — 这一块要验证什么
|
|
8
|
+
4. `docs/decisions/` — 已拍板的决策(不要重复讨论已定的)
|
|
9
|
+
|
|
10
|
+
> 这一份是给所有 AI agent 看的。Claude Code 还会再读 `CLAUDE.md`,那是它自己的额外约定。
|
|
11
|
+
|
|
12
|
+
## 项目当前阶段
|
|
13
|
+
|
|
14
|
+
**MVP 块级验证期**。按 `docs/roadmap.md` 里 `Block 0 → Block 1 → ...` 的顺序逐块推进,每块独立验证、独立审稿、独立日志。
|
|
15
|
+
**没经过当前块验证 = 不进下一块**。
|
|
16
|
+
|
|
17
|
+
## 项目结构
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
aether/
|
|
21
|
+
├── AGENTS.md ← 你在这里
|
|
22
|
+
├── CLAUDE.md ← Claude Code 专用
|
|
23
|
+
├── README.md ← 项目入口(人读)
|
|
24
|
+
├── docs/
|
|
25
|
+
│ ├── design.md ← 整体架构设计
|
|
26
|
+
│ ├── architecture.html ← 架构图
|
|
27
|
+
│ ├── roadmap.md ← 块级验证路线
|
|
28
|
+
│ └── decisions/ ← ADR(决策记录,编号单调递增)
|
|
29
|
+
├── src/ ← 跨 block 共享的基础设施
|
|
30
|
+
│ ├── llm.py ← LLM 抽象层(Anthropic SDK + base_url from env)
|
|
31
|
+
│ ├── db.py ← psycopg helpers + URL dedup + source upsert
|
|
32
|
+
│ ├── fetcher.py ← 通用 httpx wrapper
|
|
33
|
+
│ ├── config.py ← 环境变量集中读取
|
|
34
|
+
│ └── base_subgraph.py ← LangGraph subgraph ABC + 注册表
|
|
35
|
+
├── blocks/ ← 核心。按 stage 分三大类
|
|
36
|
+
│ ├── _templates/ ← 新块的标准模板
|
|
37
|
+
│ ├── sources/ ← STAGE 1 · 抓源
|
|
38
|
+
│ │ ├── basic/ ← Block 0(最小数据源)
|
|
39
|
+
│ │ ├── multi/ ← Block 1(多源)
|
|
40
|
+
│ │ └── scheduler/ ← Block 2(调度)
|
|
41
|
+
│ ├── rewrite/ ← STAGE 2 · 改写
|
|
42
|
+
│ │ ├── wechat/ ← Block 3(公众号)
|
|
43
|
+
│ │ └── xiaohongshu/ ← Block 4(小红书)
|
|
44
|
+
│ └── publish/ ← STAGE 3 · 发布
|
|
45
|
+
│ ├── e2e/ ← Block 5
|
|
46
|
+
│ ├── dashboard/ ← Block 6
|
|
47
|
+
│ └── platforms/ ← Block 7+
|
|
48
|
+
│ ├── wechat/
|
|
49
|
+
│ └── xiaohongshu/
|
|
50
|
+
│ └── <stage>/<block>/
|
|
51
|
+
│ ├── README.md ← 这一块验证什么、怎么算通过
|
|
52
|
+
│ ├── prompt.*.md ← 该块的 prompt(如有)
|
|
53
|
+
│ ├── *.py / *.ts ← 该块的代码(只放 block 专用逻辑)
|
|
54
|
+
│ ├── samples/ ← 输入样本(git 入仓)
|
|
55
|
+
│ ├── expected/ ← 手写 exemplar —— 期望长什么样
|
|
56
|
+
│ └── runs/ ← 实际跑出来的原始结果(gitignore)
|
|
57
|
+
├── logs/ ← 按日期的判断记录(人写,每次验证完写一份)
|
|
58
|
+
│ └── YYYY-MM-DD-block-NN-*.md
|
|
59
|
+
├── tests/ ← 通用测试(shared src/ 跨 block 部分在这里)
|
|
60
|
+
└── scripts/ ← 通用脚本
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**约定**:
|
|
64
|
+
- `src/` = 任何 block 都要用 → 基础设施层,稳稳放这里
|
|
65
|
+
- `blocks/<stage>/<block>/` = 单一 stage 内单一 block 的代码 + 配置 + 资产
|
|
66
|
+
- block 里的代码**只放 block 专用逻辑**:parser / state / sources.yaml / subgraph.py
|
|
67
|
+
- 通用件都搬到 `src/`:LLM、DB 连接、httpx fetch、env 配置、LangGraph 基类
|
|
68
|
+
|
|
69
|
+
## 工作方式(很关键,照做)
|
|
70
|
+
|
|
71
|
+
- **小颗粒度**:每个块是独立的最小可验证单元。没通过 → 不进下一个。
|
|
72
|
+
- **不扩散范围**:用户明确"一块一块啃",不要顺便做"这个块也顺手 X 一下"。
|
|
73
|
+
- **每次验证完写日志**:哪怕只写几行,写一份 `logs/YYYY-MM-DD-block-NN-judgment.md`。**没日志 = 没做**。
|
|
74
|
+
- **prompt 在 git、不在 DB**:风格 prompt 是核心资产,进 git 才能回滚、对比、复用。
|
|
75
|
+
- **不要主动 git push / commit**:除非用户明确说"提交"。写完文件等用户审。
|
|
76
|
+
- **不要主动 install 依赖**:除非用户明确说"装"。需要时先问。
|
|
77
|
+
- **遇到不确定的事,先查 `docs/decisions/` 和当前块的 `README.md`** —— 大概率已写。
|
|
78
|
+
- **遇到需要用户物理操作的事**(OAuth 链接、二维码、扫码、MFA 等),先自己尝试(找非交互式 flag、调整顺序、用 `--no-wait` 等),实在需要再明确告诉用户"这步需要你操作"。
|
|
79
|
+
|
|
80
|
+
## 项目当前状态
|
|
81
|
+
|
|
82
|
+
**内容领域**:英文营销生态(社媒 / 内容 / SEO / 付费广告 / 综合),目标平台微信公众号 + 小红书。详见 `README.md` 和 `docs/tech-stack.md`。
|
|
83
|
+
|
|
84
|
+
## 存储分层(很重要,照做)
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
进 git(可回滚的资产):
|
|
88
|
+
blocks/*/sources.yaml — 源白名单
|
|
89
|
+
blocks/NN-name/prompt.*.md — 风格 prompt
|
|
90
|
+
blocks/NN-name/samples/ — 输入样本
|
|
91
|
+
blocks/NN-name/expected/ — 手写 exemplar
|
|
92
|
+
logs/YYYY-MM-DD-*.md — 判断记录
|
|
93
|
+
docs/* — 设计 + 决策
|
|
94
|
+
|
|
95
|
+
进 DB(运行时数据):
|
|
96
|
+
sources.runtime 字段 — last_fetched_at / agent_status
|
|
97
|
+
articles — 抓回的文章(含 dedup + translate_status)
|
|
98
|
+
drafts — 改写产物(A/B 版本都留)
|
|
99
|
+
agent_factory — 运行时生成的 agent 配置
|
|
100
|
+
translation_cache — 多语言 LLM cache
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**不要把 sources.yaml 改成 DB 里的硬编码;DB 是 source of truth 状态,yaml 是 source of truth 配置。两边各管一块。**
|
|
104
|
+
|
|
105
|
+
## Setup
|
|
106
|
+
|
|
107
|
+
- **Python env**:`conda activate aether`(miniconda3 env,Python 3.12.13,prefix `C:\Users\13107\miniconda3\envs\aether\python.exe`)
|
|
108
|
+
- **包管理**:pip + pyproject.toml(`pip install -e ".[dev]"`;uv.lock 暂留但用 pip 装)
|
|
109
|
+
- **Postgres**:`docker compose up -d db`(详见 ADR-0004 + `docs/tech-stack.md`)
|
|
110
|
+
- **主图编排**:LangGraph 1.2+(拓扑在 `graph.py`,Block 0+ 已经用上)
|
|
111
|
+
- **LLM**:Anthropic Claude Sonnet 4(Block 3+ 启用,`.env` 占位)
|
|
112
|
+
- API key 走 `.env`(不进 git)
|
|
113
|
+
|
|
114
|
+
## 测试
|
|
115
|
+
|
|
116
|
+
v0.1 阶段**核心验证靠人的判断 + logs 记录**,不是自动化测试。Block 5+ 才引入 pytest。
|
|
117
|
+
但写代码块时,每个块配 `expected/` 手写 exemplar,作为该块的"事实标准"。
|
|
118
|
+
|
|
119
|
+
## 风格
|
|
120
|
+
|
|
121
|
+
- 文件命名:`blocks/<stage>/<block>/`(stage = sources / rewrite / publish;block 短名小写下划线),`logs/YYYY-MM-DD-block-NN-{judgment,pass,fail}.md`,`docs/decisions/NNNN-kebab-case.md`。
|
|
122
|
+
- 代码风格在引入实际代码前不定。
|
|
123
|
+
- 所有 markdown 文件首行 # 标题用人话,不用 `Aether` 这种商标味的名字。
|
|
124
|
+
|
|
125
|
+
## 决策记录
|
|
126
|
+
|
|
127
|
+
任何"以后会想回来查"的决策 → 写 `docs/decisions/NNNN-*.md`。**改了决策先加新 ADR,老 ADR 不删**。
|
|
128
|
+
|
|
129
|
+
## 安全
|
|
130
|
+
|
|
131
|
+
- API key 走 `.env`(不进 git)。
|
|
132
|
+
- 抓到的原文**不进仓**(版权 + 体积),只进 `blocks/*/samples/` 的精简版。
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Claude Code 专用。和 `AGENTS.md` 配套读,不要重复 AGENTS.md 的内容。
|
|
4
|
+
|
|
5
|
+
## 速读顺序(每次进项目先做)
|
|
6
|
+
|
|
7
|
+
1. `AGENTS.md`
|
|
8
|
+
2. `README.md`
|
|
9
|
+
3. `docs/roadmap.md`(看当前 Block)
|
|
10
|
+
4. 当前 Block 的 `blocks/NN-*/README.md`
|
|
11
|
+
|
|
12
|
+
## 几条 Claude Code 特有的约定
|
|
13
|
+
|
|
14
|
+
### prompt 编辑
|
|
15
|
+
prompt 是**核心资产**,改了要:
|
|
16
|
+
1. 跑一遍 `samples/`
|
|
17
|
+
2. 跑完写一份 `logs/YYYY-MM-DD-block-NN-judgment.md`
|
|
18
|
+
3. `git diff` 提示用户审
|
|
19
|
+
不要"为了顺手"改 prompt。
|
|
20
|
+
|
|
21
|
+
### 写代码
|
|
22
|
+
代码落在 `blocks/NN-name/` 下,**不动根目录**。除非用户明确"动其它"。
|
|
23
|
+
|
|
24
|
+
### 调试风格
|
|
25
|
+
遇到不确定的事:
|
|
26
|
+
1. 先查 `AGENTS.md` 和对应块的 `README.md`
|
|
27
|
+
2. 再查 `docs/decisions/`(说不定 ADR 已写)
|
|
28
|
+
3. 再 google / 看官方文档
|
|
29
|
+
不要直接凭直觉拍命令。
|
|
30
|
+
|
|
31
|
+
### DB 读写
|
|
32
|
+
|
|
33
|
+
- 用 `psycopg` 直连(不要 ORM);ORM 太重,v0.1 阶段没必要
|
|
34
|
+
- schema 在 `db/schema.sql`,改 schema 必须走新 migration 文件 + 改 ADR
|
|
35
|
+
- 查询 articles 时**必须**带 source_id 和/或时间窗,**禁止** `SELECT * FROM articles` 全表拉
|
|
36
|
+
- `psycopg` connection 用 `with` context,进入/退出自动 commit/rollback
|
|
37
|
+
- 事务里**不要**套 LLM 调用 —— 长事务会锁资源
|
|
38
|
+
|
|
39
|
+
## 不要做(重申 AGENTS.md 的,加上 Claude Code 特化的)
|
|
40
|
+
|
|
41
|
+
- ❌ 不要自动 `git push` / 自动 commit
|
|
42
|
+
- ❌ 不要自动 `pip install` / `npm install`
|
|
43
|
+
- ❌ 不要跨块推进
|
|
44
|
+
- ❌ 不要扩展范围("顺便 X 也做了")
|
|
45
|
+
- ❌ 不要在 root / 改 `.env` / 改 CI 配置
|
|
46
|
+
- ❌ 不要把 source URL 或原文 commit 到仓
|
|
47
|
+
|
|
48
|
+
## 调试提示
|
|
49
|
+
|
|
50
|
+
- 用 `cat` 看小文件、`head -n` 看大文件开头、`tail -n` 看结尾
|
|
51
|
+
- 不要 `rm -rf`,统一用 `trash` 工具
|
|
52
|
+
- Windows PowerShell 下用 `Get-ChildItem` / `Select-String`,不要 ls -la / grep
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aether-mkt
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: 内容分发工作流 v0.1 · 抓取英文营销内容 → 改写成公众号/小红书中文草稿
|
|
5
|
+
License: Proprietary
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: anthropic>=0.40
|
|
8
|
+
Requires-Dist: fastapi>=0.110
|
|
9
|
+
Requires-Dist: httpx>=0.27
|
|
10
|
+
Requires-Dist: jinja2>=3.1
|
|
11
|
+
Requires-Dist: langgraph>=0.2
|
|
12
|
+
Requires-Dist: playwright>=1.40
|
|
13
|
+
Requires-Dist: psycopg[binary]>=3.2
|
|
14
|
+
Requires-Dist: pydantic>=2.7
|
|
15
|
+
Requires-Dist: python-dotenv>=1.0
|
|
16
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: selectolax>=0.3
|
|
19
|
+
Requires-Dist: tenacity>=8.2
|
|
20
|
+
Requires-Dist: uvicorn[standard]>=0.27
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
23
|
+
Requires-Dist: pillow>=10.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# aether
|
|
30
|
+
|
|
31
|
+
内容分发工作流 v0.1 · MVP 验证期 · LangGraph day-1 编排
|
|
32
|
+
|
|
33
|
+
## 一句话
|
|
34
|
+
|
|
35
|
+
把英文优质内容自动抓回来,按微信公众号 + 小红书双平台风格改写成中文草稿,进入人工审核 / 发布。
|
|
36
|
+
第一阶段:单人自用,验证「双平台适配 + 降 AI 味」的核心假设。**真实平台自动发布留到 v0.2+**。
|
|
37
|
+
|
|
38
|
+
## 一键安装(macOS 用户)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
brew install postgresql@16 && brew services start postgresql@16 && createdb aether
|
|
42
|
+
pip install aether-mkt
|
|
43
|
+
aether init # 自动建表 + 引导填 LLM_API_KEY
|
|
44
|
+
aether serve # launchd 后台跑 web + 自动重启
|
|
45
|
+
# 浏览器 → http://localhost:8000/articles
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
CLI 命令:`aether {init,serve,stop,update,status,logs,uninstall}`
|
|
49
|
+
完整说明:[docs/install-mac.md](docs/install-mac.md)。
|
|
50
|
+
|
|
51
|
+
## 业务领域
|
|
52
|
+
|
|
53
|
+
- **内容来源**:英文营销生态(社媒营销、内容营销、SEO、Google ads、综合营销)——见 `blocks/sources/basic/sources.yaml`
|
|
54
|
+
- **目标平台**:微信公众号(深度长文) + 小红书(图文卡片)
|
|
55
|
+
- **核心差异**:降 AI 味 + 按平台适配的语言风格改写,**不是单纯翻译**
|
|
56
|
+
|
|
57
|
+
## 路线
|
|
58
|
+
|
|
59
|
+
按块验证,从最小可验证单元开始。**LangGraph 骨架提前铺**,每个 block = 1 个 subgraph,独立测过再接主图。
|
|
60
|
+
|
|
61
|
+
详见 [docs/roadmap.md](docs/roadmap.md)。
|
|
62
|
+
|
|
63
|
+
当前活跃块:**Block 0 · 数据源(最小)**
|
|
64
|
+
|
|
65
|
+
## 技术栈
|
|
66
|
+
|
|
67
|
+
- Python 3.11+
|
|
68
|
+
- LangGraph(主图编排,Day 1 起铺)
|
|
69
|
+
- Anthropic SDK(Block 3+ 的 LLM 调用)
|
|
70
|
+
- **PostgreSQL 16**(运行时状态库,详见 ADR-0004)
|
|
71
|
+
- pyyaml(sources 配置)+ selectolax / httpx(Block 0 解析)
|
|
72
|
+
- pytest(测试)
|
|
73
|
+
|
|
74
|
+
详见 [`pyproject.toml`](pyproject.toml)、[`docs/tech-stack.md`](docs/tech-stack.md)。
|
|
75
|
+
|
|
76
|
+
## 文档
|
|
77
|
+
|
|
78
|
+
| 我想知道 | 去看 |
|
|
79
|
+
|---|---|
|
|
80
|
+
| 整个架构设计 | [docs/design.md](docs/design.md) |
|
|
81
|
+
| 架构图(手稿的数字版) | [docs/architecture.html](docs/architecture.html) |
|
|
82
|
+
| 现在做到哪、接下来做什么 | [docs/roadmap.md](docs/roadmap.md) |
|
|
83
|
+
| 已经拍了哪些决策 | [docs/decisions/](docs/decisions/) |
|
|
84
|
+
| 每一块在验证什么 | [blocks/](blocks/) |
|
|
85
|
+
| 每次验证的判断记录 | [logs/](logs/) |
|
|
86
|
+
| 数据源白名单 | [blocks/sources/basic/sources.yaml](blocks/sources/basic/sources.yaml) |
|
|
87
|
+
|
|
88
|
+
## 协作方式
|
|
89
|
+
|
|
90
|
+
你是「开发者 + 决策者 + 第一个用户」。AI agent 是协作搭子,**不替你拍板**。
|
|
91
|
+
|
|
92
|
+
风格 prompt 不能漂 —— 都进 git,可回滚可对比。
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# aether
|
|
2
|
+
|
|
3
|
+
内容分发工作流 v0.1 · MVP 验证期 · LangGraph day-1 编排
|
|
4
|
+
|
|
5
|
+
## 一句话
|
|
6
|
+
|
|
7
|
+
把英文优质内容自动抓回来,按微信公众号 + 小红书双平台风格改写成中文草稿,进入人工审核 / 发布。
|
|
8
|
+
第一阶段:单人自用,验证「双平台适配 + 降 AI 味」的核心假设。**真实平台自动发布留到 v0.2+**。
|
|
9
|
+
|
|
10
|
+
## 一键安装(macOS 用户)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
brew install postgresql@16 && brew services start postgresql@16 && createdb aether
|
|
14
|
+
pip install aether-mkt
|
|
15
|
+
aether init # 自动建表 + 引导填 LLM_API_KEY
|
|
16
|
+
aether serve # launchd 后台跑 web + 自动重启
|
|
17
|
+
# 浏览器 → http://localhost:8000/articles
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
CLI 命令:`aether {init,serve,stop,update,status,logs,uninstall}`
|
|
21
|
+
完整说明:[docs/install-mac.md](docs/install-mac.md)。
|
|
22
|
+
|
|
23
|
+
## 业务领域
|
|
24
|
+
|
|
25
|
+
- **内容来源**:英文营销生态(社媒营销、内容营销、SEO、Google ads、综合营销)——见 `blocks/sources/basic/sources.yaml`
|
|
26
|
+
- **目标平台**:微信公众号(深度长文) + 小红书(图文卡片)
|
|
27
|
+
- **核心差异**:降 AI 味 + 按平台适配的语言风格改写,**不是单纯翻译**
|
|
28
|
+
|
|
29
|
+
## 路线
|
|
30
|
+
|
|
31
|
+
按块验证,从最小可验证单元开始。**LangGraph 骨架提前铺**,每个 block = 1 个 subgraph,独立测过再接主图。
|
|
32
|
+
|
|
33
|
+
详见 [docs/roadmap.md](docs/roadmap.md)。
|
|
34
|
+
|
|
35
|
+
当前活跃块:**Block 0 · 数据源(最小)**
|
|
36
|
+
|
|
37
|
+
## 技术栈
|
|
38
|
+
|
|
39
|
+
- Python 3.11+
|
|
40
|
+
- LangGraph(主图编排,Day 1 起铺)
|
|
41
|
+
- Anthropic SDK(Block 3+ 的 LLM 调用)
|
|
42
|
+
- **PostgreSQL 16**(运行时状态库,详见 ADR-0004)
|
|
43
|
+
- pyyaml(sources 配置)+ selectolax / httpx(Block 0 解析)
|
|
44
|
+
- pytest(测试)
|
|
45
|
+
|
|
46
|
+
详见 [`pyproject.toml`](pyproject.toml)、[`docs/tech-stack.md`](docs/tech-stack.md)。
|
|
47
|
+
|
|
48
|
+
## 文档
|
|
49
|
+
|
|
50
|
+
| 我想知道 | 去看 |
|
|
51
|
+
|---|---|
|
|
52
|
+
| 整个架构设计 | [docs/design.md](docs/design.md) |
|
|
53
|
+
| 架构图(手稿的数字版) | [docs/architecture.html](docs/architecture.html) |
|
|
54
|
+
| 现在做到哪、接下来做什么 | [docs/roadmap.md](docs/roadmap.md) |
|
|
55
|
+
| 已经拍了哪些决策 | [docs/decisions/](docs/decisions/) |
|
|
56
|
+
| 每一块在验证什么 | [blocks/](blocks/) |
|
|
57
|
+
| 每次验证的判断记录 | [logs/](logs/) |
|
|
58
|
+
| 数据源白名单 | [blocks/sources/basic/sources.yaml](blocks/sources/basic/sources.yaml) |
|
|
59
|
+
|
|
60
|
+
## 协作方式
|
|
61
|
+
|
|
62
|
+
你是「开发者 + 决策者 + 第一个用户」。AI agent 是协作搭子,**不替你拍板**。
|
|
63
|
+
|
|
64
|
+
风格 prompt 不能漂 —— 都进 git,可回滚可对比。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""aether · 内容分发 v0.1.
|
|
2
|
+
|
|
3
|
+
PyPI package: ``aether-mkt`` (the hyphenated form is reserved on PyPI)
|
|
4
|
+
CLI command: ``aether`` (cleaner to type)
|
|
5
|
+
|
|
6
|
+
Internal modules live under the ``aether`` Python package (Python
|
|
7
|
+
identifiers can't have hyphens), so ``import aether.cli`` works after
|
|
8
|
+
``pip install aether-mkt``.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|