← FEED

FEED · Agent API

REST API · COMPOSE-REQUESTS

Этот сервис не пишет посты сам — он готовит брифы (источники + стиль + база знаний) и отдаёт их через REST API. Колегин агент (Claude, ChatGPT, n8n, custom) получает share-URL → пишет пост → возвращает результат через PATCH callback.

Flow

1. Пользователь в UI:
   • выбирает посты-источники (корзина)
   • выбирает профиль (стиль + база знаний + оффер)
   • жмёт «Создать запрос»

2. UI создаёт compose-request → отдаёт share-URL вида
   http://95.111.235.10:8090/api/compose/share/x7k2m9p3.json

3. Юзер шарит share-URL агенту (один линк, никакой авторизации)

4. Агент:
   GET share-URL  → получает JSON со всем нужным
   ↓ пишет пост (по style_prompt из профиля + sources)
   PATCH callback_url с {status:"done", result_text:"..."}

5. UI видит готовый результат в «Последние запросы»

Endpoints

MethodPathОписание
GET/api/compose/share/{id}.jsonПолучить бриф (public, no auth)
PATCH/api/compose/requests/{id}Отправить результат / обновить статус
GET/api/compose/requests?status=pendingОпросить очередь (для polling-агентов)
GET/api/compose/profilesСписок профилей стиля
POST/api/compose/requestsСоздать новый бриф (UI делает за тебя)

Share JSON schema

{
  "id": "x7k2m9p3",
  "status": "pending",
  "platform": "telegram",
  "profile": {
    "name": "Founder TG",
    "style_prompt": "Пиши короткими предложениями...",
    "knowledge_base": "Я — фаундер AI/automation-стартапа...",
    "default_offer": "Подписывайся @aleksashkachannel"
  },
  "custom_brief": "(optional) сделай акцент на бизнес",
  "sources": [
    {
      "id": 123,
      "url": "https://t.me/.../456",
      "source_name": "@deksden_notes",
      "title": "...",
      "ai_summary": "Карпаты перешёл в Anthropic...",
      "content_snippet": "Полный текст оригинального поста...",
      "image_url": "https://...",
      "video_url": "",
      "has_video": false,
      "published_at": "2026-05-22T12:34:56",
      "views_count": 1600,
      "reactions_count": 89,
      "comments_count": 26
    }
  ],
  "callback_url": "http://95.111.235.10:8090/api/compose/requests/x7k2m9p3",
  "share_url": "http://95.111.235.10:8090/api/compose/share/x7k2m9p3.json"
}

Пример: curl

1. Агент скачивает бриф

SHARE_URL="http://95.111.235.10:8090/api/compose/share/x7k2m9p3.json"
BRIEF=$(curl -s "$SHARE_URL")
echo "$BRIEF" | jq '.sources[0].ai_summary'

2. Агент написал пост — отдаёт результат

curl -s -X PATCH "http://95.111.235.10:8090/api/compose/requests/x7k2m9p3" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "done",
    "result_text": "Карпаты перешёл в Anthropic. Один из создателей OpenAI и автор Tesla Autopilot теперь работает с Claude.\n\nЭто не просто кадровое решение — это вотум доверия. Anthropic выигрывает гонку талантов.\n\nПодписывайся @aleksashkachannel",
    "result_meta": {"tokens_used": 540, "model": "claude-sonnet-4-6"}
  }'

Пример: Python

import requests

SHARE = "http://95.111.235.10:8090/api/compose/share/x7k2m9p3.json"
brief = requests.get(SHARE).json()

# Build prompt from brief
profile = brief["profile"]
sources = brief["sources"]

prompt = f"""Ты пишешь пост в {brief['platform']}.

СТИЛЬ:
{profile['style_prompt']}

БАЗА ЗНАНИЙ ПРО АВТОРА:
{profile['knowledge_base']}

ИСТОЧНИКИ (синтезируй пост из них):
{chr(10).join(f"- {s.get('source_name','?')}: {s.get('ai_summary') or s.get('title','')}" for s in sources)}

ДОП. БРИФ: {brief.get('custom_brief') or '(нет)'}

ОФФЕР В КОНЦЕ:
{profile['default_offer']}

Напиши готовый пост."""

# Send to your LLM of choice (Claude, GPT, etc)
result = your_llm_call(prompt)

# Post result back
requests.patch(brief["callback_url"], json={
    "status": "done",
    "result_text": result,
    "result_meta": {"model": "claude-sonnet-4-6"},
})

Polling-режим (для агентов которым не дают share-URL вручную)

import time, requests

API = "http://95.111.235.10:8090/api/compose"

while True:
    pending = requests.get(f"{API}/requests?status=pending").json()
    for r in pending["requests"]:
        rid = r["id"]
        brief = requests.get(f"{API}/share/{rid}.json").json()
        # Mark as processing so other workers skip
        requests.patch(f"{API}/requests/{rid}", json={"status": "processing"})
        try:
            result = your_llm_call(brief)
            requests.patch(f"{API}/requests/{rid}", json={"status": "done", "result_text": result})
        except Exception as e:
            requests.patch(f"{API}/requests/{rid}", json={"status": "failed", "result_text": str(e)})
    time.sleep(30)

Status codes

statusзначение
pendingСвежий запрос, агент ещё не брал
processingАгент пишет (опционально пометить чтобы избежать race condition)
doneРезультат в result_text
failedОшибка, описание в result_text

MCP wrapper

Тонкая обёртка MCP над теми же endpoints — в планах. Пока используй REST.