models + refactor
This commit is contained in:
88
adapters/meta_adapter.py
Normal file
88
adapters/meta_adapter.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
import httpx
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
META_GRAPH_VERSION = "v18.0"
|
||||
META_GRAPH_BASE = f"https://graph.facebook.com/{META_GRAPH_VERSION}"
|
||||
|
||||
|
||||
class MetaAdapter:
|
||||
"""Adapter for Meta Platform API (Instagram Graph API).
|
||||
|
||||
Requires:
|
||||
- access_token: long-lived Page or Instagram access token
|
||||
- instagram_account_id: Instagram Business Account ID
|
||||
"""
|
||||
|
||||
def __init__(self, access_token: str, instagram_account_id: str):
|
||||
self.access_token = access_token
|
||||
self.instagram_account_id = instagram_account_id
|
||||
|
||||
async def post_to_feed(self, image_url: str, caption: str) -> Optional[str]:
|
||||
"""Upload image and publish to Instagram feed.
|
||||
|
||||
Returns the post ID on success, raises on failure.
|
||||
"""
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
# Step 1: create media container
|
||||
resp = await client.post(
|
||||
f"{META_GRAPH_BASE}/{self.instagram_account_id}/media",
|
||||
data={
|
||||
"image_url": image_url,
|
||||
"caption": caption,
|
||||
"access_token": self.access_token,
|
||||
},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
creation_id = resp.json().get("id")
|
||||
if not creation_id:
|
||||
raise ValueError(f"No creation_id from Meta API: {resp.text}")
|
||||
|
||||
# Step 2: publish
|
||||
resp2 = await client.post(
|
||||
f"{META_GRAPH_BASE}/{self.instagram_account_id}/media_publish",
|
||||
data={
|
||||
"creation_id": creation_id,
|
||||
"access_token": self.access_token,
|
||||
},
|
||||
)
|
||||
resp2.raise_for_status()
|
||||
post_id = resp2.json().get("id")
|
||||
logger.info(f"Published to Instagram feed: {post_id}")
|
||||
return post_id
|
||||
|
||||
async def post_to_story(self, image_url: str) -> Optional[str]:
|
||||
"""Upload image and publish to Instagram story.
|
||||
|
||||
Returns the story ID on success, raises on failure.
|
||||
"""
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
# Step 1: create story container
|
||||
resp = await client.post(
|
||||
f"{META_GRAPH_BASE}/{self.instagram_account_id}/media",
|
||||
data={
|
||||
"image_url": image_url,
|
||||
"media_type": "STORIES",
|
||||
"access_token": self.access_token,
|
||||
},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
creation_id = resp.json().get("id")
|
||||
if not creation_id:
|
||||
raise ValueError(f"No creation_id from Meta API: {resp.text}")
|
||||
|
||||
# Step 2: publish
|
||||
resp2 = await client.post(
|
||||
f"{META_GRAPH_BASE}/{self.instagram_account_id}/media_publish",
|
||||
data={
|
||||
"creation_id": creation_id,
|
||||
"access_token": self.access_token,
|
||||
},
|
||||
)
|
||||
resp2.raise_for_status()
|
||||
story_id = resp2.json().get("id")
|
||||
logger.info(f"Published to Instagram story: {story_id}")
|
||||
return story_id
|
||||
Reference in New Issue
Block a user