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:
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