Files
patchy631--ai-engineering-hub/content_planner_flow/scheduler.py
T
2026-07-13 12:37:47 +08:00

112 lines
3.6 KiB
Python

import os
import json
import requests
import datetime
from typing import Optional, Dict, Any
from pydantic import BaseModel
# Constants
API_URL = "https://api.typefully.com/v1/drafts/"
API_KEY = os.getenv("TYPEFULLY_API_KEY")
HEADERS = {
"X-API-KEY": f"Bearer {API_KEY}"
}
def json_to_typefully_content(thread_json: Dict[str, Any]) -> str:
"""Convert JSON thread format to Typefully's format with 4 newlines between tweets."""
tweets = thread_json['tweets']
formatted_tweets = []
for tweet in tweets:
tweet_text = tweet['content']
if 'media_urls' in tweet and tweet['media_urls']:
tweet_text += f"\n{tweet['media_urls'][0]}"
formatted_tweets.append(tweet_text)
return '\n\n\n\n'.join(formatted_tweets)
def json_to_linkedin_content(thread_json: Dict[str, Any]) -> str:
"""Convert JSON thread format to Typefully's format."""
content = thread_json['content']
if 'url' in thread_json and thread_json['url']:
content += f"\n{thread_json['url']}"
return content
def schedule_thread(
content: str,
schedule_date: str = "next-free-slot",
threadify: bool = False,
share: bool = False,
auto_retweet_enabled: bool = False,
auto_plug_enabled: bool = False
) -> Optional[Dict[str, Any]]:
"""Schedule a thread on Typefully."""
payload = {
"content": content,
"schedule-date": schedule_date,
"threadify": threadify,
"share": share,
"auto_retweet_enabled": auto_retweet_enabled,
"auto_plug_enabled": auto_plug_enabled
}
payload = {key: value for key, value in payload.items() if value is not None}
try:
response = requests.post(API_URL, json=payload, headers=HEADERS)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
return None
def schedule(
thread_model: BaseModel,
hours_from_now: int = 1,
threadify: bool = False,
share: bool = True,
post_type: str = "twitter"
) -> Optional[Dict[str, Any]]:
"""
Schedule a thread from a Pydantic model.
Args:
thread_model: Pydantic model containing thread data
hours_from_now: Hours from now to schedule the thread (default: 1)
threadify: Whether to let Typefully split the content (default: False)
share: Whether to get a share URL in response (default: True)
Returns:
API response dictionary or None if failed
"""
try:
# Convert Pydantic model to dict
thread_json = thread_model.pydantic.model_dump()
print("######## Thread JSON: ", thread_json)
# Convert to Typefully format
if post_type == "twitter":
thread_content = json_to_typefully_content(thread_json)
elif post_type == "linkedin":
thread_content = json_to_linkedin_content(thread_json)
# Calculate schedule time
schedule_date = (datetime.datetime.utcnow() +
datetime.timedelta(hours=hours_from_now)).isoformat() + "Z"
# Schedule the thread
response = schedule_thread(
content=thread_content,
schedule_date=schedule_date,
threadify=threadify,
share=share
)
if response:
print("Thread scheduled successfully!")
return response
else:
print("Failed to schedule the thread.")
return None
except Exception as e:
print(f"Error: {str(e)}")
return None