diff --git a/haixun-backend/.run/api.pid b/haixun-backend/.run/api.pid index 92f629b..3a39aa6 100644 --- a/haixun-backend/.run/api.pid +++ b/haixun-backend/.run/api.pid @@ -1 +1 @@ -34256 +19005 diff --git a/haixun-backend/.run/logs/api.log b/haixun-backend/.run/logs/api.log index 28741c3..8d5a015 100644 Binary files a/haixun-backend/.run/logs/api.log and b/haixun-backend/.run/logs/api.log differ diff --git a/haixun-backend/.run/logs/web.log b/haixun-backend/.run/logs/web.log index fc99fcd..ff9d7f5 100644 --- a/haixun-backend/.run/logs/web.log +++ b/haixun-backend/.run/logs/web.log @@ -3,7 +3,22 @@ > vite - VITE v6.4.3 ready in 146 ms + VITE v6.4.3 ready in 134 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose +9:30:54 AM [vite] (client) hmr update /src/components/OnboardingRouteGuard.tsx, /src/index.css, /src/components/MobileBottomNav.tsx, /src/components/AppSidebar.tsx, /src/onboarding/OnboardingContext.tsx +9:30:54 AM [vite] (client) hmr update /src/index.css +9:30:55 AM [vite] (client) hmr invalidate /src/onboarding/OnboardingContext.tsx Could not Fast Refresh ("useOnboarding" export is incompatible). Learn more at https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports +9:30:55 AM [vite] (client) hmr update /src/components/Layout.tsx, /src/index.css, /src/pages/PersonasPage.tsx, /src/components/OnboardingRouteGuard.tsx, /src/components/MobileBottomNav.tsx, /src/components/AccountSwitcher.tsx, /src/components/OnboardingBanner.tsx, /src/components/AppSidebar.tsx, /src/components/AccountConnectionMode.tsx, /src/components/islander/IslanderCompanion.tsx, /src/components/DevToolsPanel.tsx +9:31:02 AM [vite] (client) hmr update /src/components/AccountSwitcher.tsx, /src/index.css +9:31:02 AM [vite] (client) hmr update /src/components/MobileBottomNav.tsx, /src/index.css +9:31:02 AM [vite] (client) hmr update /src/components/AppSidebar.tsx, /src/index.css +9:31:12 AM [vite] (client) hmr update /src/components/OnboardingBanner.tsx, /src/index.css +9:31:12 AM [vite] (client) hmr update /src/components/ui.tsx, /src/index.css +9:31:12 AM [vite] (client) hmr update /src/pages/PersonasPage.tsx, /src/index.css +9:31:12 AM [vite] (client) hmr update /src/pages/ThreadsAccountConnectionsPage.tsx, /src/index.css +9:31:12 AM [vite] (client) hmr update /src/pages/SettingsPage.tsx, /src/index.css +9:31:18 AM [vite] (client) hmr update /src/pages/PersonasPage.tsx, /src/index.css +9:31:18 AM [vite] (client) hmr update /src/pages/SettingsPage.tsx, /src/index.css +9:31:23 AM [vite] (client) hmr update /src/index.css diff --git a/haixun-backend/.run/logs/worker.log b/haixun-backend/.run/logs/worker.log index f5a198f..ff2f3ca 100644 --- a/haixun-backend/.run/logs/worker.log +++ b/haixun-backend/.run/logs/worker.log @@ -2,6 +2,6 @@ > haixun-master@0.1.0 worker:style-8d > . scripts/playwright-env.sh && npx playwright install chromium && tsx haixun-backend/worker/style-8d-worker.ts -[8d-worker] started id=local-style-8d-node-34347 api=http://127.0.0.1:8890 -[8d-worker] claimed job=6a3aba8ce9d72622130957e0 template=style-8d -[8d-worker] completed job=6a3aba8ce9d72622130957e0 username=raymond0917 posts=12 +[8d-worker] started id=local-style-8d-node-19105 api=http://127.0.0.1:8890 +[8d-worker] claimed job=6a3b33a151becf68faf9ecf9 template=style-8d +[8d-worker] completed job=6a3b33a151becf68faf9ecf9 username=petopia_tw posts=12 diff --git a/haixun-backend/.run/web.pid b/haixun-backend/.run/web.pid index fcf2cb8..2a202b0 100644 --- a/haixun-backend/.run/web.pid +++ b/haixun-backend/.run/web.pid @@ -1 +1 @@ -34261 +19030 diff --git a/haixun-backend/.run/worker.pid b/haixun-backend/.run/worker.pid index 6e5fcbe..7dfbcf7 100644 --- a/haixun-backend/.run/worker.pid +++ b/haixun-backend/.run/worker.pid @@ -1 +1 @@ -34262 +19031 diff --git a/haixun-backend/AGENTS.md b/haixun-backend/AGENTS.md index 613aed7..a780e48 100644 --- a/haixun-backend/AGENTS.md +++ b/haixun-backend/AGENTS.md @@ -21,6 +21,7 @@ ## 設計文件 - `docs/job-system-plan.md`:通用 job system 規劃,包含 template、run、schedule、Redis queue/lock、取消語意與 API 草案。 +- `docs/scan-placement-plan.md`:海巡獲客(流程 B)— 知識圖譜、Brave 擴展、雙軌爬取(7 天重點 / 30 天補充)、產品匹配、島民交接。 ## 新增 API 流程 diff --git a/haixun-backend/docs/scan-placement-plan.md b/haixun-backend/docs/scan-placement-plan.md new file mode 100644 index 0000000..c38f09b --- /dev/null +++ b/haixun-backend/docs/scan-placement-plan.md @@ -0,0 +1,512 @@ +# 海巡獲客計畫:知識圖譜 + 雙軌爬取 + 島民交接 + +> 在既有「背景 Job + 島民交接」上,新增 Topic Knowledge Graph(Brave 驅動)與**雙維度 Tag**(相關 + 近期)+ **雙軌海巡**,強化流程 B 的痛點發現、關鍵字精準度與**產品-痛點匹配**驗證。 + +## 北極星 + +海巡找到的貼文/留言,**你的產品是否真的解得了那個問題**(可置入、可回覆、可追蹤)。 + +流程 B 主線: + +```text +Brave 知識圖譜擴散(周邊延伸) + → 衍生雙維度搜尋 tag(相關詞 + 近期求助詞) + → 使用者手動勾選 + → 每個 tag 雙軌爬 Threads(相關軌 + 近期軌,7d 優先 / 30d 補充) + → productFitScore 篩選 + → 島民協助撰寫獲客留言 +``` + +## 已拍板決策 + +| 項目 | 決策 | +|------|------| +| 圖譜深度 | **3 層、範圍廣**:核心 → 成因/症狀 → 相鄰情境 | +| 進海巡的 tag | **使用者手動勾選**(圖譜 UI 多選;島民可 toggle,不預設全選) | +| 近期窗口 | **7 天內為重點**;不足時補充至 **30 天**;超過 30 天排除 | +| Brave 預算 | 中等,每輪知識擴展 **10–15 次查詢**(不足可 supplemental 1 輪) | +| 痛點 tag 候選 | 圖譜衍生 **≥12 候選**,其中痛點/求助類 **≥8** | +| 流程 A | 保留 `style-8d` 捷徑;matrix + 留言收集疊加於 Phase 2 | + +--- + +## 根因診斷(舊系統痛點少、關鍵字不準) + +對照舊 Next.js([`lib/ai/prompts/research-map-placement.ts`](../../lib/ai/prompts/research-map-placement.ts)、[`lib/services/scan-tasks.ts`](../../lib/services/scan-tasks.ts)、[`lib/ai/analyze-topic.ts`](../../lib/ai/analyze-topic.ts)): + +| 現象 | 根因 | 新系統對策 | +|------|------|------------| +| 痛點只抓到 1–2 個 | Placement 壓 `suggestedTags` 至 **2~4**;`PLACEMENT_QUERY_MAX = 8` | 圖譜衍生 ≥8 痛點 tag + supplemental 補充迴圈 | +| 關鍵字不夠精準 | AI 憑種子詞推測,無外部知識 | Brave `knowledge_expand` 建 TKG,節點附 `evidence[]` | +| 只有「最相關」 | Recency 只是加分,無獨立近期軌 | **Tag 層**分 `relevance` / `recency`;**Crawl 層**雙軌必跑 | +| 沒有周邊延伸 | Brave 只做 `site:threads.net` | `knowledge_expand` 做領域知識(成因、懷孕、換季…)再衍生 tag | + +新後端原則見 [`AGENTS.md`](../AGENTS.md):**複製模式,不複製舊業務**——移植 Playwright/過濾規則,用 Mongo + Job 重建。 + +--- + +## 架構總覽 + +```mermaid +flowchart TB + subgraph input [輸入] + Seed["種子詞"] + ProductBrief["product_brief"] + Persona["人設"] + end + + subgraph tkg [知識圖譜] + ExpandJob["expand-graph job"] + BraveK["Brave knowledge_expand"] + TKG["topic_knowledge_graphs"] + end + + subgraph derive [Tag衍生] + DeriveFn["deriveSearchTagsFromGraph"] + RelQ["relevanceQueries"] + RecQ["recencyQueries"] + end + + subgraph select [使用者選擇] + GraphUI["圖譜 UI 勾選節點/tag"] + end + + subgraph scan [海巡] + ScanJob["scan job 每tag雙軌"] + Posts["scan_posts"] + end + + subgraph outcome [驗收] + Fit["productFitScore"] + Outreach["outreach + 島民留言"] + end + + Seed --> ExpandJob + ProductBrief --> ExpandJob + Persona --> ExpandJob + ExpandJob --> BraveK --> TKG + TKG --> DeriveFn + DeriveFn --> RelQ + DeriveFn --> RecQ + RelQ --> GraphUI + RecQ --> GraphUI + GraphUI --> ScanJob --> Posts --> Fit --> Outreach +``` + +--- + +## Tag 產生完整流水線 + +Tag **不是** AI 一次吐 2~4 個,而是五段流水線產出: + +```mermaid +flowchart LR + S["1 種子詞+brief"] --> A["2 AI核心地圖"] + A --> B["3 Brave knowledge_expand"] + B --> G["4 合成TKG三層"] + G --> D["5 deriveSearchTagsFromGraph"] + D --> R["relevanceQueries"] + D --> C["recencyQueries"] +``` + +| 步驟 | 做什麼 | 產出 | +|------|--------|------| +| 1 | 讀 `seed_query`、`product_brief`、`target_audience` | 輸入包 | +| 2 | AI 產核心 questions/pillars/exclusions | 研究地圖骨架 | +| 3 | Brave 10–15 次**一般網搜**(非 threadsOnly) | snippets → 候選節點 | +| 4 | AI 合成 TKG(L0/L1/L2)+ `productFitScore` + `evidence[]` | `topic_knowledge_graphs` | +| 5 | 每節點壓成 2~8 字真人搜尋詞,分兩套 | `derivedTags` | + +### 雙維度 Tag(相關 + 近期都要) + +每個圖譜節點衍生: + +| 維度 | 用途 | 寫法範例 | +|------|------|----------| +| **`relevanceQueries`** | 相關軌:短詞、高命中 | `敏感肌`、`屏障受損` | +| **`recencyQueries`** | 近期軌:求助語境 + 時間窗 | `敏感肌 請問`、`換季泛紅 推薦` | + +- `recencyQueries` 在 Brave `threads_discover` 時加 `after:{7天前日期}`(參考舊 [`scan-web-discover.ts`](../../lib/services/scan-web-discover.ts) `buildPlacementKeywordQueries`) +- 候選總量:**≥12 tag**(痛點/求助類 **≥8**);**使用者勾選後才 crawl** + +--- + +## 痛點 Tag 保底機制 + +解決「只抓到一兩個痛點」: + +```text +expand-graph 完成 → deriveSearchTagsFromGraph + IF 痛點/求助類 tag 數 < 8: + → supplemental_round(最多 1 次,Brave +5 查詢) + → 追加查詢例:{seed} 困擾、{seed} 求助、{L2節點} 請問、{seed} 推薦 + → AI 補節點 + 補 derivedTags + IF 仍 < 8: + → job 標 warning;UI + 島民提示「可重跑 expand 或手動加種子詞」 +``` + +| 指標 | 舊系統 | 新系統 | +|------|--------|--------| +| Placement suggestedTags | 2~4 | 不沿用此上限 | +| 搜尋任務上限 | 8 | 候選 ≥12,實 crawl = 勾選數 | +| 痛點類最低 | 無保證 | **≥8**(含 supplemental) | + +--- + +## Topic Knowledge Graph(TKG) + +### Mongo collection:`topic_knowledge_graphs` + +綁 `persona_id` + `seed_query`。 + +```json +{ + "seed": "敏感肌", + "nodes": [ + { + "id": "n1", + "label": "敏感肌", + "nodeKind": "pain", + "type": "core", + "layer": 0, + "placementValue": "high", + "productFitScore": 95, + "selectedForScan": false, + "evidence": [], + "derivedTags": { + "relevance": ["敏感肌"], + "recency": ["敏感肌 請問", "敏感肌 推薦"] + } + }, + { + "id": "n2", + "label": "懷孕嗅覺敏感", + "nodeKind": "cause", + "type": "cause", + "layer": 2, + "relation": "可能成因", + "placementValue": "medium", + "productFitScore": 40, + "selectedForScan": false, + "evidence": [{ "url": "...", "snippet": "..." }], + "derivedTags": { + "relevance": ["懷孕皮膚癢", "嗅覺敏感"], + "recency": ["懷孕 皮膚 癢 請益"] + } + }, + { + "id": "n3", + "label": "屏障修復原理", + "nodeKind": "knowledge", + "type": "mechanism", + "layer": 1, + "productFitScore": 70, + "selectedForScan": false, + "derivedTags": { + "relevance": ["屏障受損"], + "recency": ["屏障受損 怎麼辦"] + } + } + ], + "edges": [ + { "from": "n1", "to": "n2", "relation": "可能因" }, + { "from": "n1", "to": "n3", "relation": "機制" } + ], + "braveSources": [{ "query": "敏感肌 懷孕 原因", "snippet": "...", "url": "..." }], + "painTagCount": 9, + "generatedAt": 0 +} +``` + +### 三層擴散 + +```text +L0 核心:敏感肌 +L1 直接相關:屏障受損、換季泛紅、刺癢 +L2 周邊情境:懷孕荷爾蒙、嗅覺敏感、壓力熬夜、換洗臉產品過敏 … +``` + +### 節點語意 + +| 欄位 | 說明 | +|------|------| +| `nodeKind` | `pain`(痛點/求助)、`knowledge`(科普延伸)、`cause`、`symptom` | +| `placementValue` | 建議優先級,**不決定是否海巡** | +| `selectedForScan` | 使用者勾選後 `true`,才進 `scan` payload | +| `productFitScore` | 依 `product_brief`:產品解不解得了 | +| `derivedTags` | `relevance` + `recency` 兩套查詢詞 | +| `evidence[]` | L1/L2 必填(Brave snippet 可追溯) | + +- `knowledge` 節點:延伸話題/科普靈感,**預設不勾選**;若 snippet 含求助語境可升級為 `pain` +- `knowledge` 不強制進 placement crawl,除非使用者勾選且 `productFitScore` 達標 + +--- + +## Brave 雙模式 + +| 模式 | `threadsOnly` | 用途 | +|------|---------------|------| +| `knowledge_expand` | `false` | 建 TKG,找成因/周邊/知識 | +| `threads_discover` | `true` | 海巡時找 Threads 貼文 | + +### L0/L1 查詢模板(plan_queries,上限 15/輪) + +```text +{seed} 常見原因 +{seed} 什麼情況會 +{seed} 初期 症狀 +{seed} 怎麼改善 困擾 +{seed} 求助 推薦 +``` + +### L2 周邊擴散查詢池(從 brief/受眾推導) + +```text +{seed} 懷孕 相關 +{seed} 壓力 熬夜 +{seed} 換產品 過敏 +{seed} 與 {受眾場景} 的關係 +{L1節點} 原因 +{L1節點} 困擾 +``` + +Brave 回傳 title/snippet/url → AI 萃取節點與邊 → 寫入 TKG。實作:`internal/library/knowledge/` + Brave adapter(`BRAVE_SEARCH_API_KEY`;參考舊 [`lib/services/web-search.ts`](../../lib/services/web-search.ts))。 + +--- + +## 完整範例:敏感肌 Walkthrough + +**輸入** + +- 種子詞:`敏感肌` +- product_brief:溫和修護、無香料、適合敏感/屏障受損肌 + +**Brave knowledge_expand(節錄)** + +| 查詢 | snippet 線索 | 圖譜節點 | +|------|--------------|----------| +| `敏感肌 常見原因` | 屏障受損、過度清潔 | L1 symptom `屏障受損` | +| `敏感肌 懷孕` | 荷爾蒙、嗅覺/皮膚變敏感 | L2 cause `懷孕嗅覺敏感` | +| `換季 皮膚 泛紅` | 季節性刺激 | L1 symptom `換季泛紅` | + +**衍生 tag(候選,勾選前不 crawl)** + +| 節點 | relevanceQuery | recencyQuery | productFit | +|------|----------------|--------------|------------| +| 敏感肌 | `敏感肌` | `敏感肌 請問` | 95 | +| 屏障受損 | `屏障受損` | `屏障受損 推薦` | 90 | +| 換季泛紅 | `換季泛紅` | `換季泛紅 請問` | 88 | +| 懷孕皮膚癢 | `懷孕皮膚癢` | `懷孕 皮膚 癢 請益` | 視產品而定 | + +**使用者**:勾選 productFit 高的 4 個節點(可不勾懷孕若產品不適用) + +**startScan**:每個勾選節點的 relevance + recency 詞都跑雙軌 + +| 軌道 | 行為 | 本例預期 | +|------|------|----------| +| 相關軌 | sort=relevance, limit≈12 | 高互動痛點貼文 | +| 近期軌 | 7d 優先,不足補 30d | 一週內求助帖 | + +**合併** → gold / recent / relevant → `productFitScore` → 獲客台 → 島民 `generateOutreachReply` + fill + +--- + +## 近期窗口 + +| 窗口 | 天數 | 行為 | +|------|------|------| +| **重點** | 7 天內 | 優先爬取、優先顯示、排序最高 | +| **補充** | 8~30 天 | 7 天內不足時才補,排序較低 | +| **排除** | >30 天 | 不進海巡與獲客清單 | + +策略: + +1. 每個勾選 tag 的**近期軌**先抓滿 7 天名額 +2. 全輪痛點貼文不足目標時,自動放寬至 30 天 +3. 獲客台預設篩「7 天內」,可切「含 30 天內補充」 + +--- + +## 雙軌海巡(Tag + Crawl + UI 三層對齊) + +**近期軌不是相關軌的副產品**——每個勾選 tag 的 relevance 與 recency 查詢都**必跑**。 + +| 層級 | 相關 | 近期 | +|------|------|------| +| **Tag** | `derivedTags.relevance` 短詞高命中 | `derivedTags.recency` 求助語境 + after 日期 | +| **Crawl** | 相關軌 sort=relevance, limit≈12 | 近期軌 7d 滿額 → 30d 補 | +| **UI** | 可篩 `priority=relevant` | 預設 7d + `priority=gold` 置頂 | + +合併優先級: + +1. 兩軌皆有 → `gold` +2. 僅近期軌 → `recent` +3. 僅相關軌 → `relevant` + +過濾:移植 `hasPlacementIntent`、`looksLikeCasualChat`(舊 [`lib/topic-anchor.ts`](../../lib/topic-anchor.ts)、[`lib/scan-recency.ts`](../../lib/scan-recency.ts))。 + +### scan_posts 擴充欄位 + +- `placement_score`、`priority`(gold/recent/relevant) +- `product_fit_score`、`solved_by_product` +- `posted_at`、`search_tag`、`query_dimension`(relevance/recency) +- `graph_node_id` +- `replies[]`(可選,`scrape_replies: true`) + +--- + +## 產品匹配驗收 + +每篇海巡結果: + +- **`productFitScore`**:痛點 vs `product_brief` +- **`solvedByProduct`**:獲客留言是否對應產品能力(生成時強制檢查) + +獲客台 UI: + +- 預設排序:7 天內 + 產品能解決 +- 標示:可置入 / 需人工 / 超出產品範圍 +- 獲客留言:**島民 fill 全文,不自動送出** + +--- + +## 島民交接 + +### job.result.handoff + +```json +{ + "handoff": { + "flow": "placement", + "persona_id": "...", + "pain_tag_count": 9, + "summary": "12 候選 tag → 勾選 6 節點 → 38 篇;痛點 10(核心 6 + 周邊 4);7 天內 8 篇", + "pain_breakdown": { "core": 6, "peripheral": 4, "recent_7d": 8 }, + "top_peripheral_hits": ["懷孕皮膚癢", "換季泛紅"], + "next_route": "/personas/:id/outreach", + "needs_supplemental_expand": false, + "connection_required": false + } +} +``` + +JobMonitor → `islanderHandoffStore`;[`buildIslanderContext`](../web/src/lib/islander/buildIslanderContext.ts) 注入【近期海巡交接】。 + +### Custom actions + +| Action | 用途 | +|--------|------| +| `expandKnowledgeGraph` | 觸發 `expand-graph`;`supplemental=true` 補充迴圈 | +| `toggleGraphNode` | 勾選/取消節點 | +| `startScan` | `dual_track=true`,只爬 `selectedForScan` 節點 | +| `generateOutreachReply` | 產獲客留言 | +| `applyDraft` | fill 留言欄位 | + +### 對話路徑(流程 B) + +```text +「幫我找敏感肌的痛點」 + → expand-graph(Brave knowledge_expand + AI 合成 TKG) + → IF pain_tag_count < 8 → 島民:「要再補一輪 Brave 嗎?」→ supplemental_round + → 研究頁:圖譜 + 雙維度 tag + productFitScore + → 使用者手動勾選節點 + → startScan(每詞雙軌:相關 + 近期,7d/30d) + → outreach → highlight gold/recent → generateOutreachReply + fill +``` + +--- + +## Job 模板 + +| Template | Steps | worker | +|----------|-------|--------| +| `expand-graph` | plan_queries → brave_knowledge → ai_synth → derive_tags → [supplemental?] → persist_tkg | go | +| `scan` | session → crawl_dual_track → replies? → store → filter → ai_fit → persist | node + go | +| `style-8d` | (既有) | node + go | + +執行順序:**expand-graph → 勾選 tag → scan**。 + +--- + +## API 草案 + +```text +POST /api/v1/personas/:id/knowledge-graph/expand # ?supplemental=true +GET /api/v1/personas/:id/knowledge-graph +PATCH /api/v1/personas/:id/knowledge-graph/nodes # selectedForScan + +POST /api/v1/personas/:id/scan-jobs # graph_id, selected_node_ids, dual_track +GET /api/v1/personas/:id/scan-posts # recent_7d, product_fit_min, priority + +POST /api/v1/personas/:id/outreach-drafts/generate +``` + +Internal worker:`POST /workers/scan-posts/batch`、Brave/AI 內部端點。 + +--- + +## 前端頁面 + +| 路徑 | 用途 | 島民 label | +|------|------|------------| +| `/personas/:id/research` | 圖譜、雙維度 tag、勾選 | 加入海巡、Brave 再擴展 | +| `/personas/:id/outreach` | 獲客貼文 + 留言 | 獲客留言、標記已處理 | +| `/personas/:id/matrix` | 流程 A(Phase 2) | 草稿內容 | + +研究頁每節點展示:`relevanceQueries`、`recencyQueries`、`productFitScore`、勾選框、上次命中數。 + +--- + +## 實作分期 + +### Phase 0a — 知識圖譜 + Tag 流水線 + +- [ ] Go Brave adapter(`knowledge_expand` / `threads_discover`) +- [ ] `expand-graph` job:plan_queries → brave → ai_synth → derive_tags +- [ ] `supplemental_round`(痛點 tag < 8) +- [ ] Mongo `topic_knowledge_graphs`(含 `derivedTags`、`painTagCount`) +- [ ] `deriveSearchTagsFromGraph`(relevance + recency 雙陣列) +- [ ] API expand / get / patch nodes + +### Phase 0b — 島民 handoff + +- [ ] handoff(含 `pain_tag_count`、`needs_supplemental_expand`) +- [ ] JobMonitor bridge +- [ ] custom actions + `ai.islander.system.md` 海巡專章 + +### Phase 1 — 雙軌 scan + 流程 B + +- [ ] Node `crawl_dual_track`(每 tag 相關+近期,7d/30d) +- [ ] `productFitScore` + outreach UI +- [ ] **驗收**:敏感肌 → L2(懷孕等)→ 候選痛點 tag ≥8 → 勾選後貼文痛點 ≥8 → 7d 內 ≥5 + +### Phase 2 — 流程 A + +- [ ] matrix + 留言收集 + 島民 fill + +### Phase 3 — 自動化 + +- [ ] job_schedules、Brave 熔斷、Meta API 發留言 + +--- + +## 風險 + +| 議題 | 對策 | +|------|------| +| Brave 幻覺 | 節點必須有 `evidence[]` | +| 圖譜跑題 | exclusions + `productFitScore` | +| 查詢爆炸 | Brave ≤15/輪;supplemental ≤5;衍生 ≤20;只爬勾選 | +| 醫療敏感 | `disclaimer`;留言不自動發 | +| 周邊節點產品不符 | 低 productFit 預設不勾;獲客台標 ✗ | + +--- + +## 參考 + +- 舊海巡:[`lib/services/scan.ts`](../../lib/services/scan.ts) +- 舊網搜:[`lib/services/scan-web-discover.ts`](../../lib/services/scan-web-discover.ts) +- 舊研究地圖:[`lib/ai/analyze-topic.ts`](../../lib/ai/analyze-topic.ts) +- Job 系統:[`docs/job-system-plan.md`](./job-system-plan.md) +- 島民:[`internal/library/prompt/files/ai.islander.system.md`](../internal/library/prompt/files/ai.islander.system.md) +- 既有 8D:[`worker/style-8d-worker.ts`](../worker/style-8d-worker.ts) \ No newline at end of file diff --git a/haixun-backend/web/public/downloads/haixun-threads-sync.zip b/haixun-backend/web/public/downloads/haixun-threads-sync.zip index f9de146..d8a2a7d 100644 Binary files a/haixun-backend/web/public/downloads/haixun-threads-sync.zip and b/haixun-backend/web/public/downloads/haixun-threads-sync.zip differ diff --git a/haixun-backend/web/src/components/AccountSwitcher.tsx b/haixun-backend/web/src/components/AccountSwitcher.tsx index f5d3616..34eaac8 100644 --- a/haixun-backend/web/src/components/AccountSwitcher.tsx +++ b/haixun-backend/web/src/components/AccountSwitcher.tsx @@ -32,7 +32,8 @@ export function AccountSwitcher() { const navigate = useNavigate() const { accounts, activeAccountId, activeAccount, loading, switchAccount, createAccount } = useThreadsAccount() - const { hasAccounts, refresh: refreshOnboarding } = useOnboarding() + const { nextStep, refresh: refreshOnboarding } = useOnboarding() + const accountGuideActive = !loading && nextStep === 'account' const [open, setOpen] = useState(false) const [panel, setPanel] = useState<'list' | 'create'>('list') const [creating, setCreating] = useState(false) @@ -103,16 +104,21 @@ export function AccountSwitcher() { return (
+ {accountGuideActive && !open ? ( + + 先建立帳號 + + ) : null} - + + + + setNewName(e.target.value)} + placeholder="例如:醫療衛教、個人品牌" + onKeyDown={(e) => { + if (e.key === 'Enter') void create() + }} + /> + + + + {loading ? ( @@ -130,7 +133,9 @@ export function PersonasPage() {
) : ( -

尚無人設。建立後可設定語氣、受眾與 8D 對標分析。

+

+ 尚無人設。在上方建立第一份人設,再設定語氣、受眾與 8D 對標分析。 +

)} diff --git a/haixun-backend/web/src/pages/SettingsPage.tsx b/haixun-backend/web/src/pages/SettingsPage.tsx index f29c019..4197edb 100644 --- a/haixun-backend/web/src/pages/SettingsPage.tsx +++ b/haixun-backend/web/src/pages/SettingsPage.tsx @@ -4,11 +4,11 @@ import { AccountConnectionMode } from '../components/AccountConnectionMode' import { AccountDisplayNameSettings } from '../components/AccountDisplayNameSettings' import { ExtensionInstallCard } from '../components/ExtensionInstallCard' import { useThreadsAccount } from '../threads/ThreadsAccountContext' +import { OnboardingGuideTarget } from '../components/OnboardingGuide' import { Card, Notice, PageTitle, QuickLinkCard, SectionTitle } from '../components/ui' export function SettingsPage() { const { activeAccountId, activeAccount, loading: accountsLoading } = useThreadsAccount() - const connectionsPath = activeAccountId ? `/threads/${activeAccountId}/connections` : '/' @@ -57,9 +57,11 @@ export function SettingsPage() { /> - - - + + + + +
diff --git a/haixun-backend/web/src/pages/ThreadsAccountConnectionsPage.tsx b/haixun-backend/web/src/pages/ThreadsAccountConnectionsPage.tsx index 1a4b6e9..b99c6c4 100644 --- a/haixun-backend/web/src/pages/ThreadsAccountConnectionsPage.tsx +++ b/haixun-backend/web/src/pages/ThreadsAccountConnectionsPage.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react' import { useOutletContext, useParams } from 'react-router-dom' import { api, ApiError } from '../api/client' import { DevToolsPanel } from '../components/DevToolsPanel' +import { OnboardingGuideTarget } from '../components/OnboardingGuide' import { AcLink, Badge, Card, ErrorText, Notice, SectionTitle, SuccessText } from '../components/ui' import type { ThreadsAccountConnectionData, ThreadsAccountData } from '../types/api' @@ -37,10 +38,11 @@ export function ThreadsAccountConnectionsPage() { return (
- -
-
- Threads API 連線 + + +
+
+ Threads API 連線

正式流程的唯一通道。搜尋、發文、留言都走官方 API;帳號建立後預設使用此模式。

@@ -68,11 +70,12 @@ export function ThreadsAccountConnectionsPage() { /> )} -

- AI 產文用的 API key 在側欄「設定」管理;人設在 人設庫{' '} - 建立,發文時於 發文頁 選擇。 -

- +

+ AI 產文用的 API key 在側欄「設定」管理;人設在 人設庫{' '} + 建立,發文時於 發文頁 選擇。 +

+ + {id && connection ? (