models + refactor

This commit is contained in:
xds
2026-03-17 16:46:32 +03:00
parent e011805186
commit 14f9e7b7e9
15 changed files with 979 additions and 83 deletions

88
adapters/meta_adapter.py Normal file
View 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