Metadata-Version: 2.4
Name: ai-graph-crawler
Version: 0.9.2
Summary: AI layer for graph-crawler: graph search, LLM agents, extraction recipes, MCP and REST servers, change monitoring.
Author: 0-EternalJunior-0
License-Expression: MIT
Project-URL: Homepage, https://gitlab.com/demoprogrammer/web_graf
Project-URL: Repository, https://gitlab.com/demoprogrammer/web_graf
Project-URL: Changelog, https://gitlab.com/demoprogrammer/web_graf/-/blob/main/ai-graph-crawler/CHANGELOG.md
Project-URL: Bug Tracker, https://gitlab.com/demoprogrammer/web_graf/-/issues
Keywords: ai,agents,crawler,graph,llm,scraping,rag,mcp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: graph-crawler<6,>=5.3.2
Requires-Dist: html2md-clean<0.6,>=0.5.0
Requires-Dist: httpx>=0.27
Requires-Dist: markdown-it-py>=3.0
Requires-Dist: pydantic>=2.6
Requires-Dist: numpy>=1.26
Requires-Dist: selectolax>=0.3
Provides-Extra: openai
Requires-Dist: openai>=1.40; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40; extra == "anthropic"
Provides-Extra: gemini
Requires-Dist: openai>=1.40; extra == "gemini"
Provides-Extra: dates
Requires-Dist: htmldate>=1.9; extra == "dates"
Provides-Extra: pandas
Requires-Dist: pandas>=2.0; extra == "pandas"
Provides-Extra: bedrock
Requires-Dist: boto3>=1.35; extra == "bedrock"
Provides-Extra: emergent
Requires-Dist: emergentintegrations>=0.1; extra == "emergent"
Provides-Extra: embeddings
Requires-Dist: sentence-transformers>=3.0.0; extra == "embeddings"
Provides-Extra: faiss
Requires-Dist: faiss-cpu>=1.8; extra == "faiss"
Provides-Extra: chroma
Requires-Dist: chromadb>=0.5; extra == "chroma"
Provides-Extra: qdrant
Requires-Dist: qdrant-client>=1.10; extra == "qdrant"
Provides-Extra: pgvector
Requires-Dist: psycopg[binary]>=3.1; extra == "pgvector"
Requires-Dist: pgvector>=0.3; extra == "pgvector"
Provides-Extra: xpath
Requires-Dist: lxml>=5.0; extra == "xpath"
Provides-Extra: api
Requires-Dist: fastapi>=0.110; extra == "api"
Requires-Dist: uvicorn>=0.29; extra == "api"
Provides-Extra: mcp
Requires-Dist: mcp==2.2.0; extra == "mcp"
Provides-Extra: playwright
Requires-Dist: graph-crawler[browser]<6,>=5.3.2; extra == "playwright"
Provides-Extra: all
Requires-Dist: openai>=1.40; extra == "all"
Requires-Dist: anthropic>=0.40; extra == "all"
Requires-Dist: boto3>=1.35; extra == "all"
Requires-Dist: sentence-transformers>=3.0.0; extra == "all"
Requires-Dist: faiss-cpu>=1.8; extra == "all"
Requires-Dist: chromadb>=0.5; extra == "all"
Requires-Dist: qdrant-client>=1.10; extra == "all"
Requires-Dist: psycopg[binary]>=3.1; extra == "all"
Requires-Dist: pgvector>=0.3; extra == "all"
Requires-Dist: lxml>=5.0; extra == "all"
Requires-Dist: fastapi>=0.110; extra == "all"
Requires-Dist: uvicorn>=0.29; extra == "all"
Requires-Dist: mcp==2.2.0; extra == "all"
Requires-Dist: graph-crawler[browser]<6,>=5.3.2; extra == "all"
Requires-Dist: htmldate>=1.9; extra == "all"
Requires-Dist: pandas>=2.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: pytest-timeout>=2.2; extra == "dev"
Requires-Dist: fastapi>=0.110; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: lxml>=5.0; extra == "dev"
Requires-Dist: mcp==2.2.0; extra == "dev"
Requires-Dist: pandas>=2.0; extra == "dev"
Dynamic: license-file

# ai-graph-crawler

**Перетворює будь-який сайт на граф знань, з яким уміють працювати LLM-агенти — і люди.**

`ai-graph-crawler` (`agc`) — AI-надбудова над ядром [`graph-crawler`](../web_graf). Ядро будує граф сайту
(сторінки = ноди, посилання = ребра); `agc` додає пошук по графу, автономних агентів, детерміновану
екстракцію за схемою/рецептом, MCP-сервер для Claude Code / Cursor, моніторинг змін, контроль вартості
LLM і чесну політику збору даних у вебі 2026 року.

```
pip install "ai-graph-crawler[openai,api,mcp]"
agc adaptive https://example.com "python developer kyiv" --prefer-native --respect-policy --out site.json
agc mcp site.json --tools graph.search,graph.excerpts,graph.page      # → інструмент для Claude Code
```

---

## Навіщо

Веб 2026 року — не для скрейперів «зняв HTML → відрегекспив». Сайти публікують `llms.txt`, віддають
Markdown за `Accept: text/markdown`, декларують умови для AI-ботів у robots / `Content-Signal` / TDMRep / RSL,
беруть плату через HTTP 402. Агенти платять за токени, а LLM галюцинують на невалідованих даних.

`agc` побудований навколо трьох тез:

1. **Граф, а не список сторінок.** Структура сайту — це сигнал: де каталог, де картки, де «сироти»,
   що змінилось із минулого краулу, які сутності пов'язані.
2. **Спершу нативний канал, потім HTML, потім браузер.** Дешевше, швидше, менше токенів, поважає волю сайту.
3. **Кожен факт має провенанс і ціну.** Звідки взято, яким каналом, за якою політикою, скільки коштувало.

---

## Можливості

### Розумний краул
- **Adaptive stop** — `adaptive_crawl(url, query)` краулить, доки метрики *coverage / consistency / saturation*
  для теми не дозріють, і зупиняється сам. Жодних «max_pages=1000 і сподіваємось».
- **ChannelSelector** — для кожного URL пробує канали в порядку `llms.txt` → `Accept: text/markdown` →
  JSON-LD → API → XHR → HTML → browser. Профіль домену кешується 24 години.
- **PolicyGate** — robots для AI-агентів (`GPTBot`, `ClaudeBot`, `*`), `Content-Signal`, TDMRep well-known,
  RSL `License:`, HTTP 402 `crawler-price` → `pay | skip | alternative`. Заборонені URL не потрапляють у чергу,
  рішення пишеться в провенанс кожної ноди.
- **LiveCrawlAgent** — LLM-агент сам вирішує, куди йти далі й коли зупинитись, під бюджетом токенів.
- **Stop-conditions** ядра через `control_channel`, події прогресу (`CrawlEvent`) для WebSocket-клієнтів.

### Пошук і RAG
- **GraphIndex** — BM25, векторний, гібридний (RRF) пошук по всьому графу; `excerpts()` повертає
  релевантні фрагменти, а не сторінки цілком; `map()` — перелік URL за темою.
- **Real-time індекс** під час краулу (`LiveIndexPlugin`), інкрементальний `upsert/sync`.
- **Персистентні вектори** з ключем `node_id:content_hash`: `SqliteVectorStore` (0 залежностей), `FaissVectorStore`,
  `ChromaVectorStore`, `QdrantVectorStore`, `PGVectorStore` — незмінені сторінки не переембеддяться.
- **Канонічний Markdown** ноди через [`html2md-clean`](https://gitlab.com/demoprogrammer/html2md-clean),
  heading-aware чанкінг з overlap і semantic breakpoints, експорт у JSONL / LangChain / LlamaIndex
  або прямий інжест у векторну БД (`agc export --to qdrant://…`).

### Екстракція даних
- **CssExtractor / XPath** за JSON-портативною `ExtractionSchema` — детерміновано, без LLM.
- **ExtractionRecipe** — версійований JSON/YAML-рецепт (селектори, XHR, post-process, приклади),
  який компілюється в standalone Python, перевіряється в sandbox і лікується сам при зміні верстки
  (`DriftDetector` → `RecipeHealer` → евали на held-out → shadow → promote). Детально — [`docs/RECIPE.md`](docs/RECIPE.md).
- **LLMExtractionPlugin** — схемна екстракція з чанкінгом довгих сторінок і merge; **BatchLLMExtractor** —
  3–5 сторінок в одному промпті зі стабільним `cache_prefix`, нижчий `$/сторінку`; **DeterministicExtractor** —
  LLM один раз виводить CSS-схему для домену, далі екстракція безкоштовна.
- **EvalSuite** — golden-набори, verbatim-докази (галюцинація / пропуск), consistency між прогонами,
  gate проти baseline — рецепт не промоутиться, якщо став гіршим.
- **ParserCodegenAgent** — коли потрібен саме код: LLM бачить фінальний HTML і network-лог браузера
  (XHR-ендпойнти), пише парсер і сам себе виправляє за stderr із sandbox.

### Для агентів (agent-native)
- **MCP-сервер** `agc mcp site.json` — інструменти `graph_search`, `graph_excerpts`, `graph_map`, `graph_page`,
  `graph_extract`, `graph_entities`, `agent_search` … з `budget` у кожному виклику й `CostSnapshot` у `_meta`;
  ресурси `graph://{alias}/report|map|pages/{id}` з адресними `notifications/resources/updated`;
  read-only типово; `--print-config` → готовий `.mcp.json`. Гайд — [`docs/mcp/claude-code.md`](docs/mcp/claude-code.md).
- **REST API** `/v1` (FastAPI): graphs · tools · search · map · extract · scrape · jobs (WS-прогрес) · monitors.
- **Site-as-API** — рецепт стає OpenAPI-роутером; `/.well-known/agc.json` і `/.well-known/agent-card.json`
  дозволяють агентам самим знайти, що вміє ваш сервер.
- **Ізоляція від prompt injection** — `InjectionGuard` вирізає інструкції для моделі з веб-контенту;
  `ReaderLLM` читає недовірений текст у межах `wrap_untrusted`, `PlannerLLM` бачить лише структуровані
  підсумки й ходить тільки по `AllowList` доменів; `LiveCrawlAgent(isolate_roles=True, allow_domains=[…])`.
- **AskDataAgent** — питання природною мовою до таблиці записів («яка середня зарплата по містах?»):
  LLM повертає лише `QueryPlan` (whitelist фільтрів / group-by / агрегатів, без `eval`), план виконується
  детерміновано, кожен рядок відповіді з провенансом.

### Локальні моделі та vision
- **Дистиляція в SLM** — `distill.build_dataset(graph, recipe=)` → chat-JSONL для fine-tune (OpenAI / Ollama /
  vLLM), `slm_from_env()` підключає локальну модель як `TieredLLM.cheap`, `evaluate_slm()` міряє точність полів.
- **Vision-канал** — `VisionProbe(vlm, screenshot=)`: скріншот → VLM (`OpenAIVision` або Ollama `llava` / `qwen2-vl`)
  → Markdown; останній канал у `ChannelSelector`, вмикається явно, провенанс `channel == "vision"`.

### Живий двійник сайту
- **Monitor** — підписка `{url, pattern, query, schema, webhook, interval}` → рескан → `diff_graphs` →
  LLM-суддя «чи важлива зміна для *query*» → підписаний webhook `site.changed` (HMAC-SHA256, Stripe-стиль).
- **Шина змін** — `ChangeEvent{severity, matters, why, field_changes, section_changes}` з детермінованим
  `score_change` (правка дати чи лічильника — severity 0.05, відсікається `min_severity`); `EventBus` фан-аутить
  живим WS-клієнтам `/v1/ws/events`, `EventLog` зберігає append-only JSONL з replay `since=seq`, `WebhookSink`
  ретраїть з backoff, ідемпотентністю `X-AGC-Event-Id` і HMAC-підписом `page.changed`.
- **Пріоритет рескану** — `Monitor.plan(sub_id, budget_pages=)`: `ChangePredictor` за історією змін каже,
  які URL рескaнити першими; `Subscription(budget_pages=)` — інкрементальний рескан лише цих сторінок.
- **Колекції «Websets»** — `CollectionStore`: збережений пошук/патерн з матеріалізованим станом
  (`added / removed / changed`), MCP-ресурси `graph://{alias}/collections[/{id}]` з авто-`refresh`, REST `/v1/collections`.

### Дані для людини
- `agc report site.json --out report.md --html report.html --llms-txt llms.txt` — паспорт краулу, зміст сайту,
  таблиця записів, матриця покриття полів, таймлайн, фасети, іменний покажчик сутностей, картки сторінок —
  один самодостатній файл без CDN, кожен факт із провенансом.
- `agc diff yesterday.json today.json` — що з'явилось, змінилось, зникло; diff heading-секцій і полів.
- `agc classify | cluster | entities | kg` — тип сторінки, кластери тем, сутності (люди, організації, ціни,
  дати, контакти), knowledge graph із 3-шаровою дедуплікацією (exact → fuzzy → LLM-арбітр).

### Економіка LLM
- **CostLedger / TokenBudget** — ліміти на виклики, токени й долари; таблиця цін моделей
  (перевизначається `AGC_PRICING_JSON`), звіт «$ за правильний запис».
- **TieredLLM** — дешева модель першою, сильна лише за низької `confidence`, частка ескалацій обмежена.
- **Prompt caching** через `cache_prefix`, облік кешованих токенів.
- Провайдери: OpenAI (і сумісні: Azure, OpenRouter, vLLM, Ollama), Anthropic, AWS Bedrock, Emergent Universal Key.
  `FakeLLM` / `CassetteLLM` (record → replay) для детермінованих тестів без ключів.

---

## Швидкий старт

```bash
pip install "ai-graph-crawler[openai,api,mcp]"   # ядро graph-crawler>=5.3.2 ставиться залежністю
export OPENAI_API_KEY=...                 # або GEMINI_API_KEY / ANTHROPIC_API_KEY / AWS creds / EMERGENT_LLM_KEY
```

### 60 секунд у Python

```python
import asyncio
from ai_graph_crawler import (
    ChannelSelector, GraphIndex, LiveCrawlAgent, TokenBudget,
    adaptive_crawl, build_report, diff_graphs,
)
from ai_graph_crawler.crawl.policy import PolicyGate
from ai_graph_crawler.llm import llm_from_env
from graph_crawler import load_graph, save_graph

async def main():
    # 1. Краул до насичення теми — нативні канали, чесна політика
    graph, index, metrics = await adaptive_crawl(
        "https://example.com", "python developer kyiv",
        channels=ChannelSelector(), policy=PolicyGate(purpose="ai_input"), max_pages=200,
    )
    print(metrics.to_markdown())
    save_graph(graph, "site.json")

    # 2. Пошук по графу: гібрид BM25 + вектори, релевантні фрагменти
    for hit in index.search("remote python vacancies", mode="hybrid", top_k=5):
        print(hit.url, round(hit.score, 3))
    for ex in index.excerpts("salary range", top_k=3):
        print("…", ex.text[:120])

    # 3. Агент під бюджетом — сам вирішує, куди йти
    llm = llm_from_env()
    TokenBudget(max_calls=30, max_usd=0.50).attach(llm)
    result = await LiveCrawlAgent(llm, max_pages=40).explore("знайди всі сторінки вакансій", "https://example.com")

    # 4. Звіт для людини і diff з минулим краулом
    print(build_report(graph, index=index).to_markdown()[:2000])
    print(diff_graphs(load_graph("yesterday.json"), graph).to_markdown())

asyncio.run(main())
```

### 60 секунд у CLI

```bash
agc adaptive https://example.com "python developer kyiv" --prefer-native --respect-policy --out site.json
agc search site.json "remote python" --mode hybrid --vector-store site.db
agc report site.json --out report.md --html report.html --records-csv records.csv
agc export site.json --to qdrant://localhost:6333?collection=site --prune
agc mcp site.json --tools graph.search,graph.excerpts,graph.page --print-config > .mcp.json
agc monitor add https://example.com/jobs --pattern "/jobs/" --query "нові вакансії Python" \
    --webhook https://hooks.example/agc --secret s3cret --interval 3600 --check-now
agc monitor plan <id>                     # які URL рескaнити першими (ChangePredictor)
agc ask site.json "яка середня зарплата по містах?"      # питання до таблиці записів, без eval
agc serve --recipe jobs.yaml --graph site.json --port 8080   # REST + WS + монітори + Site-as-API
```

Повний перелік: `agc search | explore | codegen | adaptive | extract | evals | drift | heal | report | coverage |
timeline | facets | classify | cluster | entities | kg | diff | export | ask | distill | collections | serve | mcp | monitor`.

Типові сценарії з кодом і порівнянням з альтернативами — [`docs/USE_CASES.md`](docs/USE_CASES.md).

---

## Як це влаштовано

```
                 ┌──────────────────────── ai-graph-crawler (agc) ────────────────────────┐
  URL / query ──▶│ crawl/      ChannelSelector · PolicyGate · AdaptiveStop · AINode       │
                 │ index/      GraphIndex (BM25 + vectors + RRF) · VectorStore backends   │
                 │ extraction/ CssExtractor · LLMExtraction · DeterministicExtractor      │
                 │ recipe/     ExtractionRecipe · EvalSuite · Drift · Heal · Store        │
                 │ agents/     GraphSearch · LiveCrawl · ParserCodegen · AskData · Roles   │
                 │ analysis/   classify · cluster · entities · knowledge graph · diff     │
                 │ present/    Report · PageCard · Coverage · Timeline · Facets · Terms   │
                 │ serve/      MCP · REST /v1 · Jobs+WS · Monitor · ChangeEvents · Site-API│
                 │ distill/    датасет → chat-JSONL → локальна SLM як TieredLLM.cheap      │
                 │ llm/        OpenAI · Anthropic · Bedrock · Emergent · Tiered · Retry   │
                 └────────────────────────────────┬───────────────────────────────────────┘
                                                  │ плагіни ядра (ON_BEFORE_SCAN / ON_AFTER_SCAN / …)
                 ┌────────────────────────────────▼───────────────────────────────────────┐
                 │ graph-crawler 5.3 — граф сайту, драйвери (http / tls / playwright)     │
                 └────────────────────────────────────────────────────────────────────────┘
```

Кожен модуль — самостійний і підключається до ядра як плагін; усе, що потребує мережі чи LLM,
має офлайн-двійника для тестів (`FakeLLM`, `CassetteLLM`).

---

## Порівняння з альтернативами

Оцінка станом на середину 2026 року; ✅ є · ◐ частково / через зовнішні інструменти · — немає.

| Можливість | **agc** | Crawl4AI | Firecrawl | Scrapy + LLM |
|---|:-:|:-:|:-:|:-:|
| Граф сайту як первинна структура (ребра, глибина, сироти, кластери) | ✅ | — | ◐ (`/map`) | — |
| Adaptive stop за метриками теми (coverage / consistency / saturation) | ✅ | ◐ | — | — |
| Нативні канали перед HTML (`llms.txt`, `Accept: text/markdown`, JSON-LD, API) | ✅ | — | ◐ | — |
| Політика збору для AI-ботів (robots AI-UA, Content-Signal, TDMRep, RSL, HTTP 402) | ✅ | — | ◐ | ◐ (robots) |
| BM25 + векторний + гібридний пошук по всьому краулу, персистентні вектори | ✅ | ◐ | ◐ (search) | — |
| Детермінована екстракція без LLM (CSS/XPath-схема) | ✅ | ✅ | ◐ | ✅ |
| Версійовані рецепти + евали + self-healing при зміні верстки | ✅ | — | — | — |
| Кодогенерація парсера з network-логом браузера і sandbox | ✅ | ◐ | — | — |
| MCP-сервер з бюджетами, `CostSnapshot` і live-оновленням ресурсів | ✅ | ◐ | ◐ | — |
| Site-as-API: рецепт → OpenAPI + `/.well-known/agc.json` / agent-card | ✅ | — | — | — |
| Моніторинг змін: LLM-суддя, severity подій, предиктор рескану, підписані webhook-и з replay | ✅ | — | ◐ | — |
| Облік вартості LLM у $ і «$ за правильний запис», tiered-роутинг моделей | ✅ | — | — | — |
| Ізоляція planner/reader від prompt injection | ✅ | — | — | — |
| Звіт для людини (Markdown/HTML/llms.txt) з провенансом кожного факту | ✅ | — | — | — |
| Знання/сутності: NER + knowledge graph з дедуплікацією | ✅ | — | ◐ | — |
| Дистиляція у локальну SLM, vision-fallback, питання до даних без `eval` | ✅ | ◐ | — | — |
| Локально, open source, без хостованого сервісу | ✅ | ✅ | ◐ (self-host) | ✅ |
| Керований хостинг з масштабуванням | — | — | ✅ | — |

`agc` не намагається бути хостованим сервісом — це бібліотека й CLI, які ви запускаєте у своєму процесі,
контейнері або як MCP-сервер поруч зі своїм агентом.

---

## Конфігурація

| Змінна | Призначення |
|---|---|
| `AGC_LLM` | `openai` \| `anthropic` \| `bedrock` \| `gemini` \| `emergent`; без неї — авто-детект за ключами `OPENAI_API_KEY` → `ANTHROPIC_API_KEY` → AWS creds → `GEMINI_API_KEY` → `EMERGENT_LLM_KEY` |
| `GEMINI_MODEL` | модель Gemini (типово `gemini-3.5-flash`; дешевше — `gemini-3.5-flash-lite`) |
| `AGC_LOG_LEVEL` | рівень логів CLI (типово `WARNING`) |
| `OPENAI_MODEL` / `ANTHROPIC_MODEL` / `BEDROCK_MODEL` / `EMERGENT_PROVIDER`+`EMERGENT_MODEL` | модель провайдера (типово `gpt-4o-mini`, `claude-haiku-4-5`, `eu.amazon.nova-lite-v1:0`, `openai`/`gpt-4o-mini`); для `gpt-5*`/`o*` автоматично використовуються `max_completion_tokens` без `temperature` |
| `OPENAI_BASE_URL` | OpenAI-сумісні бекенди: Azure, OpenRouter, vLLM, Ollama |
| `AGC_PRICING_JSON` | шлях або inline JSON із цінами моделей для `CostLedger` |
| `AGC_STATE_DIR` | стан моніторів (`monitors.json`, знімки графів); типово `.agc` |
| `AGC_CACHE_DIR` | профілі доменів і політики; типово `~/.cache/agc` |
| `AGC_SCHEMA_CACHE` | кеш схем `DeterministicExtractor` |

Extras: `[openai] [anthropic] [bedrock] [gemini] [emergent] [dates] [pandas] [embeddings] [faiss] [chroma] [qdrant] [pgvector] [xpath] [api] [mcp] [playwright] [all] [dev]`.

### Docker

```bash
docker compose up agc-api                           # REST на :8080, стан і кеш — у volume /data
docker compose run --rm agc-report                  # разовий звіт по ./graphs/site.json
```

---

## Документація

| Документ | Про що |
|---|---|
| [`docs/USE_CASES.md`](docs/USE_CASES.md) | 12 типових сценаріїв з кодом, CLI і порівнянням з альтернативами |
| [`docs/RECIPE.md`](docs/RECIPE.md) | `ExtractionRecipe`: модель, API, приклад JSON, roadmap |
| [`docs/mcp/claude-code.md`](docs/mcp/claude-code.md) | Підключення до Claude Code / Cursor / Claude Desktop, контракт інструментів, live-ресурси |

## Ліцензія

MIT.
