ปัญหา
พลอยเพิ่งเริ่มทำช่อง TikTok ployspective (พัฒนาตัวเอง + เรื่องผู้หญิง + UX) แบบจริงจัง
เธอไม่ได้ขาดไอเดีย — เธอมี list อยู่แล้วและมีเยอะเกินไป ปัญหาคือไม่รู้ว่าควรเริ่มทำแนวไหนก่อน
เป้าหมายคือ ลดเวลาลองผิดลองถูก โดยเรียนจากคลิปที่พิสูจน์แล้วว่าเวิร์ก แล้วเอามาปรับกับเรื่องของตัวเอง
เป้าหมาย
เว็บส่วนตัวที่อัปเดตอัตโนมัติทุกสัปดาห์ แสดงคลิป TikTok ที่ "สูตรพาไป" — ช่องเล็กแต่ยอดวิวทะลุ — ในนิชใกล้เคียงกับช่องพลอย ทั้งไทยและต่างประเทศ พร้อมสคริปต์ถอดคำและบทวิเคราะห์ว่าทำไมคลิปนั้นถึงเวิร์ก
หลักคิดสำคัญ: ไม่ตามช่องใหญ่ คลิปของช่อง 2 ล้านผู้ติดตามที่ได้ 1 ล้านวิว เกิดจากฐานแฟน ไม่ใช่สูตร — ลอกไม่ได้ สิ่งที่ช่องใหม่ลอกได้คือคลิปของช่องเล็กที่ได้วิวผิดปกติ เพราะนั่นแปลว่าตัวคอนเทนต์เองพาไป
นอกขอบเขต (รอบนี้)
เก็บไว้พิจารณาเฟสถัดไป หลังจากพลอยได้ใช้ของจริงแล้ว เท่านั้น:
- การยุบคลิปเป็น "สูตร" (format library) และจัดอันดับสูตร
- การจับคู่สูตรกับ list ไอเดียของพลอยอัตโนมัติ
- Feedback loop เรียนรู้จากผลคลิปที่พลอยลงเอง
- การร่างสคริปต์/hook ให้
- การติดตามเสียง/เพลงมาแรง
ผู้ใช้
พลอย (คนเดียว, ไม่ใช่สายเทค) เข้าผ่านมือถือเป็นหลัก Joey เข้าไปดู/ปรับ config ได้เหมือนกัน
สถาปัตยกรรม
สี่ชิ้นแยกกันชัด แต่ละชิ้นทดสอบเดี่ยวได้:
[1] harvest.py Apify TikTok scraper → คลิปดิบ → Supabase.clips
↓
[2] score.py คำนวณคะแนน + กรอง → เลือก top N → selected = true
↓
[3] analyze.py ซับ/ถอดเสียง → Gemini วิเคราะห์ → Supabase.clip_analysis
↓
[4] web/ Next.js อ่าน Supabase → การ์ดเรียงตามคะแนน
ร้อยเข้าด้วยกันด้วย systemd timer รายสัปดาห์ (คืนวันอาทิตย์) ไม่ใช้ n8n โดยตั้งใจ — โปรเจกต์นี้ไม่ควรไปพัวพันกับ workflow ที่รันงานอื่นอยู่ และ n8n ไม่ได้เพิ่มอะไรให้ pipeline ที่เป็นเส้นตรงแบบนี้
หน้าที่ของแต่ละชิ้น
| ชิ้น | รับอะไร | คืนอะไร | พึ่งอะไร |
|---|---|---|---|
harvest.py |
list คำค้นจาก queries |
เขียน clips แถวใหม่ |
Apify API |
score.py |
แถว clips ที่ยังไม่ให้คะแนน |
อัปเดต outlier_score, selected, reject_reason |
ไม่พึ่งอะไรเลย (ฟังก์ชันบริสุทธิ์ + I/O บาง) |
analyze.py |
clips ที่ selected = true |
เขียน clip_analysis |
OpenRouter/Gemini, ซับจาก Apify |
web/ |
Supabase | HTML | Supabase |
score.py แยกตรรกะการให้คะแนนออกเป็นฟังก์ชันบริสุทธิ์ในไฟล์เดียว มี unit test ครอบ — เพราะเป็นส่วนที่จะต้องจูนบ่อยที่สุด
ที่อยู่และการเข้าถึง
- โค้ด:
~/ploy - พอร์ต: 3044 (ตรวจแล้วว่าว่าง)
- โดเมน:
ploy.theingress.coผ่าน Caddy reverse proxy - systemd:
ploy.service(เว็บ) +ploy-harvest.timer(รายสัปดาห์) - ไม่มีล็อกอิน — เปิด URL แล้วเข้าได้เลย ใส่
noindexกัน search engine เก็บ ยอมรับความเสี่ยงว่าใครเจอ URL ก็เข้าดูได้ เพราะเนื้อหาไม่มีอะไรเป็นความลับ และการไม่มีรหัสทำให้พลอยใช้ง่ายที่สุด
หน้าสเปกฉบับนี้อยู่ที่ test.theingress.co (static จาก ~/ploy/site) แยกจากตัวแอป
ที่เก็บข้อมูล
Supabase project vps_n8n_apify_new (free tier ตัวที่ active อยู่)
queries — list คำค้น แก้ได้จากหน้าเว็บ
id, term, kind (hashtag|keyword), lang (th|en), enabled, created_at
clips — คลิปดิบ + คะแนน
id, tiktok_id (unique), url, author_handle, author_followers, views, likes, comments, shares, saves, duration_sec, posted_at, caption, hashtags, thumbnail_url, is_slideshow, lang, source_query_id, harvested_at, outlier_score, save_rate, selected, reject_reason, bookmarked, user_note
clip_analysis — ผลวิเคราะห์
clip_id (fk), transcript, transcript_source (subtitle|gemini), hook_text, structure_beats (jsonb), on_screen_text, why_it_worked, model, analyzed_at
สูตรคัดคลิป
outlier_score = views / max(author_followers, 1000)
save_rate = saves / views
ตัดทิ้งก่อนจัดอันดับ (บันทึกเหตุผลใน reject_reason เสมอ เพื่อให้จูนเกณฑ์ได้จากข้อมูลจริง):
| เกณฑ์ | เหตุผล |
|---|---|
| อายุ > 60 วัน | สูตรเก่าตายแล้ว |
| ผู้ติดตาม > 500,000 | เทียบกับช่องพลอยไม่ได้ |
| วิว < 50,000 | เผื่อกรณีใช้ leastDiggs ที่ฝั่ง Apify ไม่ได้ — กันคลิปวิวน้อยที่คะแนนสวยเพราะช่องเล็กมาก |
| ยาว < 15 วินาที | สั้นเกินกว่าจะมีโครงให้เรียน |
| เป็น slideshow ภาพนิ่ง | คนละรูปแบบกับที่พลอยทำ |
caption ติด #ad / #โฆษณา / ลิงก์ affiliate |
คลิปขายของ ไม่ใช่คอนเทนต์ |
| เป็น duet / stitch | โครงยืมของคนอื่นมา |
save_rate < 0.5% |
วิวมาจากเพลง/การปั่น ไม่ใช่ตัวคอนเทนต์ |
| ช่องเดิมที่เคยขึ้นใน 4 สัปดาห์ก่อน | กันเห็นซ้ำ |
จำกัด 2 คลิปต่อช่อง ในผลลัพธ์ที่เลือก กันช่องเดียวยึดหน้าจอ เลือก 20 คลิปต่อสัปดาห์ ส่งต่อไปขั้นวิเคราะห์
ค่าตัวเลขทุกตัวข้างบนเป็น ค่าเริ่มต้นที่รอ spike ยืนยัน และปรับได้จากหน้า settings
โดยเฉพาะ save_rate < 0.5% ที่ตั้งจากการคาดการณ์ล้วนๆ ต้องดูการกระจายตัวจริงจาก spike ก่อน
ทำไมใช้ save_rate ไม่ใช่แค่ไลก์
ไลก์คือ "ผ่านตาแล้วชอบ" แต่การเซฟคือ "มีค่าพอที่จะกลับมาดูอีก" สำหรับคอนเทนต์สายพัฒนาตัวเอง อัตราการเซฟเป็นสัญญาณคุณภาพที่แม่นกว่าไลก์มาก และอัลกอริทึม TikTok ให้น้ำหนักเซฟกับแชร์สูง
ต้นทุน
ราคาจริงของ clockworks/tiktok-scraper ดึงจาก Apify API เมื่อ 2026-08-09 (FREE tier):
| event | ราคา |
|---|---|
| ผลลัพธ์ 1 คลิป | $0.0037 |
add-on: กรองความนิยม (leastDiggs) |
+$0.0013 |
| add-on: กรองวันที่ | +$0.0013 |
| add-on: proxy ประเทศ | +$0.0013 |
| add-on: ถอดเสียง | $0.048/นาที/คลิป |
| เริ่มรัน | $0.001 |
ไม่ใช้บริการถอดเสียงของ Apify — $0.048 ต่อคลิปแพงกว่า Gemini ผ่าน OpenRouter หลายเท่า
ใช้ DOWNLOAD_SUBTITLES (ซับที่ TikTok มีให้ ไม่มีค่า add-on) แล้วคลิปที่ไม่มีซับค่อยส่ง Gemini
ทำไมกรองที่ฝั่ง Apify ถึงคุ้ม: ผลลัพธ์แพงขึ้น 35% แต่แทบทุกอันใช้ได้ ดึงดิบ 250 คลิป = $0.93 แต่ผ่านเกณฑ์จริงอาจเหลือ ~40 → $0.023 ต่อคลิปที่ใช้ได้ ดึงแบบกรอง 120 คลิป = $0.60 ได้ของใช้ได้มากกว่า → งบเท่าเดิมได้ของประมาณสองเท่า
ประมาณการ: ~$0.75/สัปดาห์ ≈ $3/เดือน พอดีกับฟรีคีย์ 1 ก้อน ($5/เดือน) แบบมีที่เหลือหายใจ
ทุกรันต้องตั้ง maxTotalChargeUsd เป็น hard cap เสมอ
เรื่องคีย์ Apify
Spike ใช้คีย์ sandtiger (เหลือ $1.07 ณ 2026-07-27) โดยตั้ง cap $0.35 ต่อรัน
เพื่อไม่ให้กระทบ Competitor Ads Sync ที่ต้องใช้คีย์เดียวกันจนถึงรอบ reset 14 ส.ค.
สำหรับการรันประจำสัปดาห์ ต้องสมัครฟรีคีย์ใหม่เฉพาะโปรเจกต์นี้ ก่อนเปิดใช้ timer
อัปเดตตารางเครดิตใน ~/note/apify-api-key.md ทุกครั้งที่ใช้เครดิต
หน้าเว็บ (สามหน้าเท่านั้น)
หน้าหลัก — การ์ดเรียงตามคะแนน แต่ละใบ: ธัมบ์เนล, ยอดวิว / ผู้ติดตาม / คะแนน outlier, hook สามวินาทีแรก, แท็บกรองไทย/EN, ปุ่มบุ๊กมาร์ก
หน้าคลิป — สคริปต์เต็ม, โครงคลิปแบ่งตามวินาที, ข้อความบนจอ, "ทำไมมันเวิร์ก", ลิงก์ไปดูของจริงบน TikTok, ช่องจดโน้ตของพลอย
หน้าตั้งค่า — แก้ list คำค้น/แฮชแท็ก (เปิด/ปิดรายตัว) และค่าเกณฑ์กรอง
คำค้นตั้งต้น ~15 คำ ให้พลอยแก้เองได้: ไทย — พัฒนาตัวเอง, มายด์เซ็ต, ผู้หญิงเก่ง, ทำงานออฟฟิศ, uxdesign, ออกแบบ ux อังกฤษ — selfimprovement, mindsetshift, womenintech, uxtips, careeradvice, productivity
Phase 0 — Spike (ต้องทำก่อนเขียนเว็บ)
มีสมมติฐานสามข้อที่ถ้าผิดจะล้มดีไซน์ทั้งอัน ต้องพิสูจน์ด้วยเงินจริงประมาณ $0.30 ก่อน
คำถามที่ spike ต้องตอบ
- actor คืนจำนวนผู้ติดตามของเจ้าของคลิปหรือไม่ (
authorMeta.fansหรือเทียบเท่า) ถ้าไม่คืน →outlier_scoreคำนวณไม่ได้เลย ต้องเปลี่ยนวิธีวัดทั้งหมด - ค่า add-on กรองความนิยม คิดต่อคลิป หรือต่อรอบรัน
คำอธิบายของ Apify กำกวม วัดจาก
chargedEventCountsของรันจริง - ซับไทยของ TikTok มีจริงกี่เปอร์เซ็นต์ ถ้าคลิปไทยส่วนใหญ่ไม่มีซับ ต้องพึ่ง Gemini ดูวิดีโอ — ซึ่งต้องเช็คด้วยว่าโหลดวิดีโอจาก VPS ได้จริง (TikTok มักบล็อก IP ดาต้าเซ็นเตอร์)
คำถามรอง
leastDiggsค่าไหนให้ "ต้นทุนต่อคลิปที่ใช้ได้จริง" ต่ำสุด — ทดสอบ 5,000 / 10,000 / 30,000 (ข้อสังเกต: 100,000 ไลก์ ≈ 1–2 ล้านวิว ซึ่งเกือบทั้งหมดมาจากช่องใหญ่ที่เราตั้งใจตัดออกอยู่แล้ว)proxyCountryCode = THทำให้ผลค้นหาภาษาไทยตรงขึ้นจริงไหม — คุ้มกับ +35% หรือเปล่าleastDiggsใช้ร่วมกับกรองวันที่ไม่ได้ (เอกสาร Apify ระบุไว้) — ต้นทุนที่เสียไปกับคลิปเก่าเป็นเท่าไหร่videoSearchSortingและvideoSearchDateFilterขึ้นสถานะ UNDER MAINTENANCE — ยังใช้ไม่ได้จริงไหม
วิธีทำ
ยิงคำค้นตัวอย่าง 3–4 คำ (ไทย 2 อังกฤษ 2) หลาย threshold รันละไม่เกิน 30 ผลลัพธ์
ทุกรันตั้ง maxTotalChargeUsd = 0.35
บันทึกผลดิบ + chargedEventCounts ไว้ที่ ~/ployspective/spike/
เกณฑ์ผ่าน
- ตอบคำถามข้อ 1–3 ได้ด้วยข้อมูลจริง ไม่ใช่การอนุมาน
- ได้ค่า
leastDiggsและเกณฑ์กรองที่ยืนยันด้วยตัวเลข - ประมาณการต้นทุนรายสัปดาห์ที่วัดได้จริง ไม่ใช่ตัวเลขจากป้ายราคา
หลัง spike จบ กลับมาแก้สเปกนี้ด้วยตัวเลขจริง แล้วค่อยเขียนแผน implementation
การทดสอบ
score.py— unit test ครอบทุกเกณฑ์กรองและการคำนวณคะแนน รวมถึงเคสหารด้วยศูนย์และผู้ติดตามเป็น 0harvest.py/analyze.py— ทดสอบด้วย fixture จากผลจริงของ spike ไม่ยิง API ในเทสต์- เว็บ — ตรวจหน้าจริงด้วย Playwright บน headless Chrome ก่อนบอกว่าเสร็จ (ทั้ง render และ console error)
การจัดการความผิดพลาด
- Apify ล้มเหลว / เครดิตหมด (402) → บันทึก log, ไม่เขียนทับข้อมูลเดิม, เว็บยังแสดงของสัปดาห์ก่อน
- คลิปไหนวิเคราะห์ไม่ได้ → ข้ามตัวนั้น ไม่ล้มทั้งรอบ, ทำเครื่องหมายไว้ให้เห็นบนเว็บ
- ทุกรันบันทึกจำนวนคลิปที่ดึงมา/ผ่านเกณฑ์/วิเคราะห์สำเร็จ และค่าใช้จ่ายจริง เพื่อให้เห็นว่าระบบเสื่อมเมื่อไหร่
ความเสี่ยง
| ความเสี่ยง | ผลกระทบ | ทางรับมือ |
|---|---|---|
| actor ไม่คืนจำนวนผู้ติดตาม | ดีไซน์ล้ม | spike ข้อ 1 ก่อนสร้างอะไร |
| TikTok บล็อก VPS ตอนโหลดวิดีโอ | ถอดสคริปต์ไม่ได้ | ใช้ URL วิดีโอที่ Apify คืนมาแทน yt-dlp |
| เครดิต Apify หมดกลางคัน | ระบบหยุด | hard cap ทุกรัน + คีย์แยกเฉพาะโปรเจกต์ |
| พลอยเปิดดูสองครั้งแล้วเลิกใช้ | เสียเวลาเปล่า | ขอบเขตเล็กโดยตั้งใจ ตัดสินใจทำเฟสต่อไปจากการใช้จริงเท่านั้น |
| คำค้นตั้งต้นไม่ตรงนิช | ได้คลิปไม่เกี่ยว | หน้า settings แก้ได้เอง + รีวิวผลรอบแรกกับพลอย |
ความลับ
Apify token, OpenRouter key, Supabase key เก็บใน ~/.env.secrets เท่านั้น
ห้ามใส่ค่าจริงลงในไฟล์ในโปรเจกต์หรือเอกสาร