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 месяцев включена"
}| Поле | Тип | Описание |
|---|---|---|
lemma | string | Леммa (базовая форма слова) |
competitor_avg_score | float | Средний proximity-score у конкурентов |
own_score | float | Score на вашей странице (0.0 = отсутствует в контексте запроса) |
gap | float | competitor_avg_score − own_score. Выше = приоритетнее |
coverage_percent | float | % конкурентов, у которых слово в сильном контексте |
recommendation | string | Куда добавить: Title/H1, H2/H3, тело, списки |
context_snippet | string | Пример фразы с конкурентских страниц |
"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 сущностей:
| Значение | Источников |
|---|---|
core | 3+ конкурентов |
main | 2 конкурента |
additional | 1 конкурент |
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')}")