přidán skript digest-bot.py
This commit is contained in:
115
digest-bot.py
Normal file
115
digest-bot.py
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
import csv
|
||||
import requests
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
# Config
|
||||
CSV_PATH = '/app/data/posts-latest.csv'
|
||||
CLAUDE_API = 'https://api.anthropic.com/v1/messages'
|
||||
CLAUDE_KEY = os.getenv('ANTHROPIC_API_KEY')
|
||||
MASTODON_URL = 'https://zpravobot.news'
|
||||
|
||||
# Bot selection
|
||||
bot_name = sys.argv[1] if len(sys.argv) > 1 else 'zpravobot'
|
||||
TOKENS = {
|
||||
'zpravobot': os.getenv('TOKEN_ZPRAVOBOT'),
|
||||
'pozitivni': os.getenv('TOKEN_POZITIVNI'),
|
||||
'sarkasticky': os.getenv('TOKEN_SARKASTICKY')
|
||||
}
|
||||
|
||||
if bot_name not in TOKENS:
|
||||
print(f"❌ Unknown bot: {bot_name}")
|
||||
sys.exit(1)
|
||||
|
||||
TOKEN = TOKENS[bot_name]
|
||||
|
||||
if not TOKEN or not CLAUDE_KEY:
|
||||
print(f"❌ Missing env variables")
|
||||
sys.exit(1)
|
||||
|
||||
# 1. Load posts
|
||||
try:
|
||||
with open(CSV_PATH, 'r', encoding='utf-8') as f:
|
||||
posts = list(csv.DictReader(f))
|
||||
print(f"📊 Loaded {len(posts)} posts for @{bot_name}")
|
||||
except Exception as e:
|
||||
print(f"❌ Error loading CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 2. Prepare data for Claude
|
||||
posts_sample = posts[:500] # Limit to 500 posts
|
||||
posts_json = json.dumps(posts_sample, ensure_ascii=False)
|
||||
|
||||
# 3. Claude API
|
||||
print("🤖 Calling Claude API...")
|
||||
try:
|
||||
response = requests.post(
|
||||
CLAUDE_API,
|
||||
headers={
|
||||
'x-api-key': CLAUDE_KEY,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
json={
|
||||
'model': 'claude-sonnet-4-20250514',
|
||||
'max_tokens': 4000,
|
||||
'messages': [{
|
||||
'role': 'user',
|
||||
'content': f'Vytvoř denní digest pro bot @{bot_name}. Data: {posts_json[:10000]}'
|
||||
}]
|
||||
},
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"❌ Claude API error: {response.text}")
|
||||
sys.exit(1)
|
||||
|
||||
digest = response.json()['content'][0]['text']
|
||||
print(f"✅ Claude response: {len(digest)} chars")
|
||||
except Exception as e:
|
||||
print(f"❌ Claude API exception: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 4. Split to 2 toots (500 chars limit)
|
||||
toot1 = digest[:500]
|
||||
toot2 = digest[500:1000] if len(digest) > 500 else None
|
||||
|
||||
# 5. Publish toot 1
|
||||
print("📤 Publishing toot 1...")
|
||||
try:
|
||||
r1 = requests.post(
|
||||
f'{MASTODON_URL}/api/v1/statuses',
|
||||
headers={'Authorization': f'Bearer {TOKEN}'},
|
||||
json={'status': toot1}
|
||||
)
|
||||
|
||||
if r1.status_code not in [200, 201]:
|
||||
print(f"❌ Mastodon error: {r1.text}")
|
||||
sys.exit(1)
|
||||
|
||||
toot1_id = r1.json()['id']
|
||||
print(f"✅ Toot 1 published: {toot1_id}")
|
||||
except Exception as e:
|
||||
print(f"❌ Mastodon exception: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 6. Publish toot 2 (if exists)
|
||||
if toot2:
|
||||
print("📤 Publishing toot 2...")
|
||||
try:
|
||||
r2 = requests.post(
|
||||
f'{MASTODON_URL}/api/v1/statuses',
|
||||
headers={'Authorization': f'Bearer {TOKEN}'},
|
||||
json={
|
||||
'status': toot2,
|
||||
'in_reply_to_id': toot1_id
|
||||
}
|
||||
)
|
||||
print(f"✅ Toot 2 published (thread)")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Toot 2 failed: {e}")
|
||||
|
||||
print(f"✅ Done! Published to @{bot_name}")
|
||||
Reference in New Issue
Block a user