Skip to content

GET /api/v1/process/status/

Возвращает поток событий (Server-Sent Events) с прогрессом и финальным результатом анализа.

Запрос

http
GET /api/v1/process/status/{task_id}
Authorization: Bearer YOUR_KEY
Accept: text/event-stream

События потока

Каждое событие — JSON-объект в строке data: {...}.

PENDING

json
{"state": "PENDING", "progress": 0}

PROCESSING / PROGRESS

json
{
  "state": "PROGRESS",
  "progress": 45,
  "details": {
    "step": "analysis_internal",
    "message": "Computing TF-IDF vectors"
  }
}

SUCCESS

json
{
  "state": "SUCCESS",
  "progress": 100,
  "result": {
    "Umbrella Analysis": [...],
    "Block Comparison": [...],
    "N-grams Analysis": [...],
    "Anchors Analysis": [...],
    "Triplets Analysis": {...}
  }
}

FAILURE

json
{
  "state": "FAILURE",
  "error": {
    "code": 1001,
    "message": "Failed to parse page: connection timeout"
  }
}

Структура result

Ключи в ответе используют читаемые названия (не snake_case):

КлючВсегдаОписание
"Umbrella Analysis"Зонтичный анализ — слова для добавления
"Block Comparison"TF-IDF сравнение плотности слов
"N-grams Analysis"Анализ фраз
"Anchors Analysis"Анализ анкоров со ссылками
"Triplets Analysis"⚡ extendedГраф знаний (только при triplet_analysis: true)

"Umbrella Analysis" — элемент

json
{
  "lemma": "гарантия",
  "competitor_avg_score": 1.84,
  "own_score": 0.0,
  "gap": 1.84,
  "coverage_percent": 75.0,
  "recommendation": "Добавить в H2/H3",
  "context_snippet": "гарантия 12 месяцев включена"
}
ПолеТипОписание
lemmastringЛеммa (базовая форма слова)
competitor_avg_scorefloatСредний proximity-score у конкурентов
own_scorefloatScore на вашей странице (0.0 = отсутствует в контексте запроса)
gapfloatcompetitor_avg_score − own_score. Выше = приоритетнее
coverage_percentfloat% конкурентов, у которых слово в сильном контексте
recommendationstringКуда добавить: Title/H1, H2/H3, тело, списки
context_snippetstringПример фразы с конкурентских страниц

"Block Comparison" — элемент

json
{
  "word": "матрас",
  "lemma": "матрас",
  "frequency": 8.3,
  "frequency_own_page": 2,
  "pct_target_comp_avg": -45.2,
  "action_needed": "Увеличить",
  "present_on_own_page": true
}

"N-grams Analysis" — элемент

json
{
  "ngram": "бесплатная доставка",
  "ngram_type": "bigrams",
  "pages_count": 4,
  "frequency_avg": 2.5,
  "present_on_own_page": false
}

"Anchors Analysis" — элемент

json
{
  "anchor": "купить сейчас",
  "frequency_own": 0,
  "frequency_comp_avg": 3.2,
  "pages_count": 3,
  "links": ["https://comp1.com/shop", "https://comp2.com/store"]
}

"Triplets Analysis"

json
{
  "entities": [
    {
      "subject": "Матрас",
      "tier": "core",
      "triplets_count": 12,
      "sources_count": 4,
      "triplets": [
        {
          "predicate": "материал наполнителя",
          "object": "независимые пружины",
          "sources": ["comp1.com", "comp2.com"]
        }
      ]
    }
  ],
  "missing_triplets": {
    "critical": [{"subject": "Чехол", "tier": "core", ...}],
    "important": [...],
    "unique": [...]
  },
  "stats": {
    "total_triplets": 87,
    "sources_with_content": 5,
    "gaps_critical": 3,
    "gaps_important": 8,
    "gaps_unique": 21,
    "gaps_total": 32,
    "batches": 5
  }
}

Tier сущностей:

ЗначениеИсточников
core3+ конкурентов
main2 конкурента
additional1 конкурент
uniqueупоминается один раз

Пример обработки — Python

python
import requests, json

BASE = "https://unihra.ru/api/v1"
HEADERS = {"Authorization": "Bearer YOUR_KEY"}

task_id = "550e8400-e29b-41d4-a716-446655440000"

with requests.get(f"{BASE}/process/status/{task_id}", headers=HEADERS, stream=True) as resp:
    for line in resp.iter_lines():
        if not line or not line.startswith(b"data: "):
            continue
        event = json.loads(line[6:])
        state = event["state"]

        if state == "PROGRESS":
            print(f"[{event['progress']}%] {event.get('details', {}).get('message', '')}")

        elif state == "SUCCESS":
            result = event["result"]
            gaps = result.get("Umbrella Analysis", [])
            print(f"Зонтичный анализ: {len(gaps)} пробелов")
            for g in gaps[:5]:
                print(f"  {g['lemma']:20s} gap={g['gap']:.2f}{g['recommendation']}")
            break

        elif state == "FAILURE":
            err = event.get("error", {})
            raise RuntimeError(f"[{err.get('code')}] {err.get('message')}")