feat: Facebook Status Automation
- สร้างระบบ automation สำหรับ Facebook status draft - Two-pass system: sessions → filter → compare → draft - Ban list สำหรับกิจกรรมซ้ำทุกวัน - Compare กับ 10 โพสย้อนหลัง (ไม่โพสซ้ำ) - Draft style: คนทั่วไปอ่านเข้าใจ ไม่ใช้ technical jargon - Cron: รันทุกวัน 20:00 น. Components: - facebook-status-generator.py (script) - SKILL.md (Hermes skill) - README.md (docs)
This commit is contained in:
119
facebook-status-automation/README.md
Normal file
119
facebook-status-automation/README.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Facebook Status Automation
|
||||
|
||||
ระบบสร้าง Facebook status draft อัตโนมัติจาก Hermes sessions
|
||||
|
||||
## 🎯 วัตถุประสงค์
|
||||
|
||||
สร้าง personal brand โดย:
|
||||
- อัพเดทสิ่งที่ทำให้คนเห็น (แต่ไม่โพสซ้ำ)
|
||||
- เขียนให้คนที่ไม่รู้เรื่อง IT อ่านเข้าใจ
|
||||
- โชว์ skill + mindset ผ่านงานจริง
|
||||
|
||||
## 📋 Logic
|
||||
|
||||
```
|
||||
Sessions 24h → Filter (ban list) → Compare (10 posts) → Draft
|
||||
```
|
||||
|
||||
### Ban List
|
||||
|
||||
กิจกรรมที่ทำซ้ำทุกวัน → ไม่ต้องเอามาโพส:
|
||||
- `ai-news-reading`
|
||||
- `morning-news-briefing`
|
||||
- `daily-planning`
|
||||
- `start-my-day`
|
||||
- `end-my-day`
|
||||
- `cron-model-update`
|
||||
- `cookie-renewal`
|
||||
|
||||
### Comparison Rules
|
||||
|
||||
| เงื่อนไข | ผลลัพธ์ |
|
||||
|---------|---------|
|
||||
| อยู่ใน ban list | ❌ skip |
|
||||
| เรื่องเดิม + โพสวันนี้แล้ว | ❌ skip |
|
||||
| เรื่องเดิม + ไม่มี change ใหม่ | ❌ skip |
|
||||
| เรื่องเดิม + มี change ใหม่ | ✅ โพส (แก้ wording) |
|
||||
| เรื่องใหม่ | ✅ โพส |
|
||||
| ไม่มีเรื่องน่าสนใจ | 🔕 ไม่โพส |
|
||||
|
||||
## 📂 ไฟล์
|
||||
|
||||
```
|
||||
facebook-status-automation/
|
||||
├── facebook-status-generator.py # script หลัก
|
||||
├── README.md # เอกสารนี้
|
||||
└── SKILL.md # Hermes skill (TODO)
|
||||
```
|
||||
|
||||
## 🔧 การใช้งาน
|
||||
|
||||
### Test Run (Manual)
|
||||
|
||||
```bash
|
||||
cd /Users/kunthawat/Gitea/moreminimore-personal-system/facebook-status-automation
|
||||
python3 facebook-status-generator.py
|
||||
```
|
||||
|
||||
### Cron Job (Auto)
|
||||
|
||||
รันทุกวัน 20:00 น. (8 โมงเย็น)
|
||||
|
||||
```bash
|
||||
hermes cron create \
|
||||
--name "Facebook Status Draft" \
|
||||
--schedule "0 20 * * *" \
|
||||
--script facebook-status-generator.py \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
## 📊 Log File
|
||||
|
||||
`~/vault/.facebook-status-log.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"lookback_posts": 10,
|
||||
"ban_list": [...]
|
||||
},
|
||||
"posts": [
|
||||
{
|
||||
"date": "2026-07-02",
|
||||
"topics": ["ai-news-automation", "moreminimore-service"],
|
||||
"draft": "...",
|
||||
"article_link": null
|
||||
}
|
||||
],
|
||||
"milestones": {
|
||||
"ai-news-automation": {
|
||||
"last_posted": "2026-07-02",
|
||||
"last_change": "2026-06-25"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎨 Draft Style
|
||||
|
||||
- ไม่มี technical jargon
|
||||
- เน้นผลลัพธ์/ประโยชน์
|
||||
- คนทั่วไปอ่านเข้าใจ
|
||||
- สั้นกระชับ
|
||||
|
||||
### ✅ ดี
|
||||
|
||||
> วันนี้ปรับระบบ AI ให้สรุปข่าวอัตโนมัติทุกเช้า — ประหยัดเวลา 1 ชม./วัน
|
||||
|
||||
### ❌ ไม่ดี
|
||||
|
||||
> Today I updated the cron job configuration to use the moreminimore-ai model via custom LLM proxy
|
||||
|
||||
## 🔮 TODO
|
||||
|
||||
- [ ] สร้าง Hermes skill
|
||||
- [ ] เชื่อม session_search จริง (ตอนนี้ mock)
|
||||
- [ ] ใช้ LLM สรุปกิจกรรม (ตอนนี้ keyword matching)
|
||||
- [ ] ใช้ humanizer skill ปรับ draft
|
||||
- [ ] เช็ค blog articles + ใส่ link
|
||||
- [ ] Support multiple languages
|
||||
157
facebook-status-automation/SKILL.md
Normal file
157
facebook-status-automation/SKILL.md
Normal file
@@ -0,0 +1,157 @@
|
||||
---
|
||||
name: facebook-status-automation
|
||||
description: "Generate Facebook personal status drafts from recent Hermes sessions. Two-pass system: extract activities from 24h sessions → compare with last 10 posts → output copyable draft or skip if nothing new."
|
||||
version: 1.0.0
|
||||
author: Kunthawat
|
||||
license: MIT
|
||||
platforms: [macos, linux]
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [social-media, facebook, personal-brand, automation]
|
||||
category: productivity
|
||||
---
|
||||
|
||||
# Facebook Status Automation
|
||||
|
||||
สร้าง Facebook status draft จาก Hermes sessions ใน 24 ชม. ย้อนหลัง
|
||||
มุ่งเป้า: **personal brand** สำหรับคนทั่วไปที่ไม่รู้เรื่อง IT
|
||||
|
||||
## When to use
|
||||
|
||||
- ผู้ใช้ขอให้สร้าง Facebook status จากสิ่งที่ทำวันนี้
|
||||
- Cron job รันตอน 20:00 ทุกวัน
|
||||
- ผู้ใช้ถามว่า "วันนี้มีอะไรน่าโพสไหม"
|
||||
|
||||
## Core Logic
|
||||
|
||||
```
|
||||
1. session_search(limit=20, sort="newest") → ดึง sessions 24h ย้อนหลัง
|
||||
2. อ่าน session content → สรุปกิจกรรม
|
||||
3. Filter: กรอง ban list (กิจกรรมซ้ำทุกวัน)
|
||||
4. Compare: เปรียบเทียบกับ 10 โพสย้อนหลัง (จาก .facebook-status-log.json)
|
||||
5. Draft: สร้าง status ถ้ามีเรื่องใหม่ / skip ถ้าไม่มี
|
||||
```
|
||||
|
||||
## Ban List
|
||||
|
||||
กิจกรรมที่ทำทุกวัน → ไม่ต้องโพส:
|
||||
|
||||
| Topic | เหตุผล |
|
||||
|-------|--------|
|
||||
| ai-news-reading / morning-news-briefing | cron รันทุกวัน |
|
||||
| daily-planning / start-my-day | cron รันทุกวัน |
|
||||
| end-my-day / evening-wrapup | cron รันทุกวัน |
|
||||
| cron-model-update | internal config |
|
||||
| cookie-renewal | internal maintenance |
|
||||
|
||||
เพิ่ม/ลบได้ใน `~/vault/.facebook-status-log.json` → `settings.ban_list`
|
||||
|
||||
## Comparison Rules
|
||||
|
||||
| เงื่อนไข | ผลลัพธ์ |
|
||||
|---------|---------|
|
||||
| อยู่ใน ban list | ❌ skip |
|
||||
| เรื่องเดิม + โพสวันนี้แล้ว | ❌ skip |
|
||||
| เรื่องเดิม + ไม่มี change ใหม่ (lookback_posts) | ❌ skip |
|
||||
| เรื่องเดิม + มี change ใหม่ | ✅ โพส (ปรับ wording) |
|
||||
| เรื่องใหม่ | ✅ โพส |
|
||||
| ไม่มีเรื่องน่าสนใจ | 🔕 ไม่โพส → แจ้ง "วันนี้ไม่มีเรื่องน่าโพส" |
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. ดึง Sessions
|
||||
|
||||
```
|
||||
session_search(limit=20, sort="newest")
|
||||
```
|
||||
|
||||
กรองเฉพาะ sessions ใน 24 ชม. ย้อนหลัง (ไม่ใช่ทุก session)
|
||||
|
||||
### 2. อ่าน + สรุปกิจกรรม
|
||||
|
||||
อ่าน content ของแต่ละ session → สรุปว่า:
|
||||
- ทำอะไรไปบ้าง
|
||||
- มี progress/achievement อะไรบ้าง
|
||||
- มี blog article ไหม (ถ้ามี เก็บ link)
|
||||
|
||||
### 3. Filter Ban List
|
||||
|
||||
เปรียบเทียบ topic กับ ban_list ใน log file
|
||||
ถ้า match → skip
|
||||
|
||||
### 4. Compare กับ 10 โพสย้อนหลัง
|
||||
|
||||
อ่าน `~/vault/.facebook-status-log.json`
|
||||
- ดึง posts 10 ตัวล่าสุด
|
||||
- เช็คว่า topic นี้เคยโพสหรือยัง
|
||||
- ถ้าเคย → เช็คว่ามี change ใหม่ไหม
|
||||
|
||||
### 5. สร้าง Draft (ถ้าผ่าน)
|
||||
|
||||
เขียน Facebook status:
|
||||
- ไม่ใช้ technical jargon
|
||||
- เน้นผลลัพธ์/ประโยชน์สำหรับคนทั่วไป
|
||||
- สั้น กระชับ
|
||||
- ใส่ blog link ถ้ามี
|
||||
|
||||
### 6. อัพเดท Log
|
||||
|
||||
บันทึกลง `~/vault/.facebook-status-log.json`:
|
||||
- เพิ่ม post entry ใหม่
|
||||
- อัพเดท milestones
|
||||
|
||||
### 7. Output
|
||||
|
||||
ถ้ามี draft → แสดงให้ user copy
|
||||
ถ้าไม่มี → แจ้ง "วันนี้ไม่มีเรื่องน่าโพส"
|
||||
|
||||
## Draft Style Guide
|
||||
|
||||
### ✅ เขียนแบบนี้
|
||||
|
||||
```
|
||||
วันนี้ปรับระบบ AI ให้สรุปข่าวอัตโนมัติทุกเช้า — เขียน script ให้ทำงานเองตอน 7 โมง ไม่ต้องนั่งเปิดทีละเว็บ
|
||||
```
|
||||
|
||||
### ❌ ไม่เขียนแบบนี้
|
||||
|
||||
```
|
||||
Today I updated the cron job configuration to use the moreminimore-ai model
|
||||
via custom LLM proxy endpoint for all scheduled tasks
|
||||
```
|
||||
|
||||
### Rules
|
||||
|
||||
- เขียนเป็นไทย (หรือภาษาที่ user ต้องการ)
|
||||
- ไม่ใช้คำ technical (cron, API, script → ใช้คำที่คนทั่วไปเข้าใจ)
|
||||
- เน้น **สิ่งที่ได้** ไม่ใช่ **สิ่งที่ทำ** ("ประหยัดเวลา" ดีกว่า "ปรับ config")
|
||||
- ไม่ต้องใส่ timestamp หรือเวลาที่ทำ
|
||||
- ถ้ามี blog article → ใส่ link ท้ายโพส
|
||||
|
||||
## Files
|
||||
|
||||
| ไฟล์ | ที่อยู่ | หน้าที่ |
|
||||
|-----|--------|--------|
|
||||
| Log file | `~/vault/.facebook-status-log.json` | เก็บประวัติ + milestones |
|
||||
| Script | `~/Gitea/moreminimore-personal-system/facebook-status-automation/facebook-status-generator.py` | Test run / debug |
|
||||
| Skill | `~/.hermes/skills/productivity/facebook-status-automation/SKILL.md` | ไฟล์นี้ |
|
||||
|
||||
## Cron Setup
|
||||
|
||||
```bash
|
||||
# รันทุกวัน 20:00 น.
|
||||
hermes cron create \
|
||||
--name "Facebook Status Draft" \
|
||||
--schedule "0 20 * * *" \
|
||||
--prompt "รัน facebook-status-automation skill" \
|
||||
--skills facebook-status-automation \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
## Pitfalls
|
||||
|
||||
1. **sessions 24h ≠ sessions ทั้งหมด** — ต้อง filter เวลาจริง ไม่ใช่ดึงทุก session
|
||||
2. **ban list ต้องตรง topic ไม่ใช่ substring** — เช่น "morning-news-briefing" ต้องเช็คว่า topic match เต็ม ไม่ใช่แค่มี "morning" อยู่
|
||||
3. **draft ต้อง human-readable** — ห้ามมี technical terms หลุดไป
|
||||
4. **log file ต้อง update ทุกครั้งที่โพส** — ไม่งั้นจะโพสซ้ำ
|
||||
5. **ถ้าไม่มีเรื่องน่าโพส → ไม่ต้องโพส** — ห้าม forced output
|
||||
238
facebook-status-automation/facebook-status-generator.py
Normal file
238
facebook-status-automation/facebook-status-generator.py
Normal file
@@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Facebook Status Automation
|
||||
สร้าง Facebook status draft จาก Hermes sessions ใน 24 ชม. ย้อนหลัง
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
# Hermes tools available in cron context
|
||||
from hermes_tools import terminal
|
||||
|
||||
|
||||
def load_log(log_path):
|
||||
"""โหลดไฟล์ log"""
|
||||
result = terminal(f"cat {log_path}")
|
||||
return json.loads(result["output"])
|
||||
|
||||
|
||||
def save_log(log_path, data):
|
||||
"""บันทึกไฟล์ log"""
|
||||
content = json.dumps(data, indent=2, ensure_ascii=False)
|
||||
with open(log_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def get_recent_sessions():
|
||||
"""ดึง sessions ใน 24 ชม. ย้อนหลัง (mock — จริง ๆ ต้อง call session_search)"""
|
||||
# ใน production: from hermes_tools import session_search
|
||||
# results = session_search(limit=20, sort="newest")
|
||||
|
||||
# Mock data สำหรับ test
|
||||
return [
|
||||
{"session_id": "20260702_105243_1a22ad", "title": "ปรับ cron ให้ใช้ moreminimore AI", "source": "tui"},
|
||||
{"session_id": "20260626_101627_b0c64f", "title": "วางแผน moreminimore-service", "source": "tui"},
|
||||
{"session_id": "cron_93fb9da1b231_20260702_090030", "title": "Morning News Briefing", "source": "cron"},
|
||||
{"session_id": "cron_437e59dedd0e_20260702_070016", "title": "orbites-start-my-day", "source": "cron"},
|
||||
]
|
||||
|
||||
|
||||
def extract_activities(sessions, ban_list):
|
||||
"""
|
||||
สกัดกิจกรรมจาก sessions + กรองตาม ban list
|
||||
|
||||
ใน production ต้อง:
|
||||
1. อ่าน session content จริง (session_search + scroll)
|
||||
2. ใช้ LLM สรุปว่าทำอะไรไปบ้าง
|
||||
3. กรอง ban list
|
||||
|
||||
ตอนนี้ mock ไว้ก่อน
|
||||
"""
|
||||
activities = []
|
||||
|
||||
for s in sessions:
|
||||
title = s["title"].lower()
|
||||
|
||||
# Simple keyword matching (ใน production ใช้ LLM)
|
||||
if "cron" in title and "model" in title:
|
||||
activities.append({
|
||||
"topic": "cron-model-update",
|
||||
"description": "ปรับ cron ให้ใช้ moreminimore AI model",
|
||||
"session": s["title"]
|
||||
})
|
||||
elif "moreminimore-service" in title:
|
||||
activities.append({
|
||||
"topic": "moreminimore-service",
|
||||
"description": "วางแผน moreminimore-service",
|
||||
"session": s["title"]
|
||||
})
|
||||
elif "morning news" in title or "briefing" in title:
|
||||
activities.append({
|
||||
"topic": "morning-news-briefing",
|
||||
"description": "Morning News Briefing รัน",
|
||||
"session": s["title"]
|
||||
})
|
||||
elif "start-my-day" in title:
|
||||
activities.append({
|
||||
"topic": "start-my-day",
|
||||
"description": "orbites-start-my-day รัน",
|
||||
"session": s["title"]
|
||||
})
|
||||
|
||||
# กรองตาม ban list
|
||||
kept = []
|
||||
skipped = []
|
||||
|
||||
for a in activities:
|
||||
if any(ban in a["topic"] for ban in ban_list):
|
||||
skipped.append({**a, "reason": "อยู่ใน ban list"})
|
||||
else:
|
||||
kept.append(a)
|
||||
|
||||
return kept, skipped
|
||||
|
||||
|
||||
def compare_with_history(candidates, log_data, today):
|
||||
"""เปรียบเทียบกับ 10 โพสย้อนหลัง"""
|
||||
posts = log_data["posts"]
|
||||
lookback_posts = posts[-log_data["settings"]["lookback_posts"]:]
|
||||
milestones = log_data["milestones"]
|
||||
|
||||
final_keep = []
|
||||
final_skip = []
|
||||
|
||||
for candidate in candidates:
|
||||
topic = candidate["topic"]
|
||||
|
||||
# หาว่าเคยโพสเรื่องนี้ไหม
|
||||
posted_before = False
|
||||
last_posted_date = None
|
||||
|
||||
for post in lookback_posts:
|
||||
if topic in post["topics"]:
|
||||
posted_before = True
|
||||
last_posted_date = post["date"]
|
||||
break
|
||||
|
||||
if not posted_before:
|
||||
# ไม่เคยโพส → โพสได้
|
||||
final_keep.append({**candidate, "reason": "🆕 เรื่องใหม่"})
|
||||
else:
|
||||
# เคยโพสแล้ว
|
||||
if last_posted_date == today:
|
||||
# โพสวันนี้แล้ว → SKIP
|
||||
final_skip.append({**candidate, "reason": f"❌ เคยโพสวันนี้แล้ว"})
|
||||
else:
|
||||
# โพสวันอื่น → ดูว่ามี change ใหม่ไหม
|
||||
milestone = milestones.get(topic, {})
|
||||
last_change = milestone.get("last_change", "")
|
||||
|
||||
if last_change == today:
|
||||
# มี change วันนี้ → โพสได้
|
||||
final_keep.append({**candidate, "reason": f"🔄 มี change ใหม่"})
|
||||
else:
|
||||
# ไม่มี change → SKIP
|
||||
final_skip.append({**candidate, "reason": f"❌ ไม่มี change ใหม่ (last: {last_change})"})
|
||||
|
||||
return final_keep, final_skip
|
||||
|
||||
|
||||
def create_draft(candidates):
|
||||
"""สร้าง Facebook status draft"""
|
||||
if not candidates:
|
||||
return None
|
||||
|
||||
# Simple template (ใน production ใช้ LLM + humanizer)
|
||||
lines = []
|
||||
for c in candidates:
|
||||
lines.append(c["description"])
|
||||
|
||||
draft = "\n\n".join(lines)
|
||||
return draft
|
||||
|
||||
|
||||
def update_log(log_data, today, draft, topics):
|
||||
"""อัพเดท log file"""
|
||||
# เพิ่ม post ใหม่
|
||||
log_data["posts"].append({
|
||||
"date": today,
|
||||
"topics": topics,
|
||||
"draft": draft,
|
||||
"article_link": None
|
||||
})
|
||||
|
||||
# อัพเดท milestones
|
||||
for topic in topics:
|
||||
log_data["milestones"][topic] = {
|
||||
"last_posted": today,
|
||||
"last_change": today
|
||||
}
|
||||
|
||||
return log_data
|
||||
|
||||
|
||||
def main():
|
||||
log_path = Path.home() / "vault" / ".facebook-status-log.json"
|
||||
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
||||
|
||||
print("=" * 60)
|
||||
print("📋 Facebook Status Automation")
|
||||
print("=" * 60)
|
||||
print(f"Date: {today}")
|
||||
print()
|
||||
|
||||
# 1. โหลด log
|
||||
log_data = load_log(log_path)
|
||||
ban_list = log_data["settings"]["ban_list"]
|
||||
|
||||
# 2. ดึง sessions
|
||||
print("🔎 Fetching sessions (24h)...")
|
||||
sessions = get_recent_sessions()
|
||||
print(f" Found: {len(sessions)} sessions")
|
||||
|
||||
# 3. สกัดกิจกรรม + กรอง ban list
|
||||
print("\n🚫 Filtering activities...")
|
||||
kept, skipped = extract_activities(sessions, ban_list)
|
||||
print(f" Kept: {len(kept)}, Skipped: {len(skipped)}")
|
||||
|
||||
if not kept:
|
||||
print("\n🔕 No activities after ban filter")
|
||||
print("=" * 60)
|
||||
return
|
||||
|
||||
# 4. เปรียบเทียบกับ history
|
||||
print("\n🔍 Comparing with history...")
|
||||
final_keep, final_skip = compare_with_history(kept, log_data, today)
|
||||
print(f" Can post: {len(final_keep)}")
|
||||
|
||||
if not final_keep:
|
||||
print("\n🔕 วันนี้ไม่มีเรื่องใหม่น่าโพส")
|
||||
print("\nเหตุผล:")
|
||||
for item in final_skip:
|
||||
print(f" • {item['description']}: {item['reason']}")
|
||||
print("=" * 60)
|
||||
return
|
||||
|
||||
# 5. สร้าง draft
|
||||
print("\n📝 Generating draft...")
|
||||
draft = create_draft(final_keep)
|
||||
topics = [c["topic"] for c in final_keep]
|
||||
|
||||
# 6. อัพเดท log
|
||||
log_data = update_log(log_data, today, draft, topics)
|
||||
save_log(log_path, log_data)
|
||||
print(" ✅ Log updated")
|
||||
|
||||
# 7. แสดง draft
|
||||
print("\n" + "=" * 60)
|
||||
print("📝 DRAFT สำหรับ copy:")
|
||||
print("=" * 60)
|
||||
print(draft)
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user