Python CLI + API приложение для базового SEO-анализа целевого сайта, сравнения с конкурентами и генерации SEO-ядра.
Текущий статус: Phase 4 backend MVP: CLI + FastAPI + async jobs + file-backed artifacts.
- CLI-команда
analyze - CLI-команда
search - анализ локального HTML-файла, URL или домена
- эвристическое определение ниши по SEO-сигналам страницы
- извлечение title, meta description, headings, links, keywords
- сравнение целевой страницы с конкурентами
- генерация SEO-core / keyword opportunities
- прямой поиск по ключевой фразе через SERP provider
- query-driven competitor discovery из SERP
- поддержка
geo,language,device,search_engine - сохранение до 10 SERP результатов и выбор primary top-5 shortlist
- page type classification для target / SERP / competitors
- bounded crawl mode для target site с
--page-limit - LLM provider abstraction
- local heuristic enrichment provider по умолчанию
- Ollama provider for external local or cloud LLM inference
- task-aware prompt versioning (
phase3-v3/*) for structured enrichment - automatic Ollama retry on invalid/truncated JSON responses
- niche summary, opportunity scoring и content-gap explanations
- page recommendations и content brief draft
- FastAPI server mode (
serve) - async background jobs for
analyzeandsearch - file-backed persistence for job metadata and result artifacts
- export artifacts in
json,text,markdown, andcsv - default report output in
data/ - default report naming:
<website>_analysis_<date>and<website>_search_<date> - вывод в
textиjson - загрузка списка конкурентов из JSON через
--serp-file
- реальный SERP crawling из Google / Perplexity API
- кластеризация на уровне всего сайта
- PostgreSQL / Redis production persistence
- dashboard и scheduled re-runs
agentic-search-optimization-engine/
├── main.py
├── pyproject.toml
├── README.md
├── SOW.md
├── ARCHITECTURE.md
├── TODO.md
├── seo_agent_cli/
│ ├── __init__.py
│ ├── __main__.py
│ ├── analyzer.py
│ ├── cli.py
│ ├── crawler.py
│ ├── extractors.py
│ ├── heuristics.py
│ ├── jobs.py
│ ├── llm.py
│ ├── models.py
│ ├── reporters.py
│ ├── search.py
│ ├── server.py
│ └── serp.py
└── tests/
├── fixtures/
├── test_analyzer.py
├── test_cli.py
├── test_extractors.py
├── test_llm.py
├── test_search.py
└── test_server.py
- Python
>= 3.14 - зависимости backend MVP:
fastapi,uvicorn,httpx
Из корня проекта:
cd /c/dev/agentic-search-optimization-engine
python -m pip install -e .
python -m unittest discover -s tests -v
python main.py analyze --site tests/fixtures/target_site.html --competitor tests/fixtures/competitor_agency.html --competitor tests/fixtures/competitor_content.html --max-core 10 --format text
python main.py search --query "купить машину украина" --top 5 --format text
python main.py analyze --site tests/fixtures/target_site.html --competitor tests/fixtures/competitor_agency.html --competitor tests/fixtures/competitor_content.html --llm-provider local --brief-audience "SEO manager" --max-core 8 --format text
python main.py analyze --site tests/fixtures/target_site.html --competitor tests/fixtures/competitor_agency.html --competitor tests/fixtures/competitor_content.html --llm-provider ollama --llm-model deepseek-v3.2:cloud --llm-timeout 250 --brief-audience "SEO manager" --max-core 8 --format json
python main.py serve --host 127.0.0.1 --port 8000 --artifacts-dir datapython main.py analyze \
--site tests/fixtures/target_site.html \
--competitor tests/fixtures/competitor_agency.html \
--competitor tests/fixtures/competitor_content.html \
--format textpython main.py analyze \
--site tests/fixtures/target_site.html \
--competitor tests/fixtures/competitor_agency.html \
--format jsonЕсли --output не задан, отчёт по умолчанию будет сохранён в data/ c именем вида:
target-site_analysis_20260405.json
python main.py analyze \
--site tests/fixtures/target_site.html \
--serp-file tests/fixtures/serp_results.json \
--max-competitors 5 \
--max-core 15Пример:
python main.py search \
--query "купить машину украина" \
--top 5 \
--format textJSON-режим:
python main.py search \
--query "купить машину украина" \
--top 5 \
--format jsonЕсли --output не задан, search report по умолчанию будет сохранён в data/ c именем вида:
auto-ria_search_20260405.json
Если нужен дополнительный анализ найденных страниц:
python main.py search \
--query "купить машину украина" \
--top 5 \
--analyze-pages \
--format textpython main.py search \
--query "купить машину украина" \
--provider file \
--serp-source tests/fixtures/duckduckgo_search_results.html \
--top 3 \
--format textЕсли у тебя есть целевой сайт и нужно автоматически подтянуть конкурентов из SERP по ключу:
python main.py analyze \
--site tests/fixtures/target_site.html \
--query "купить машину украина" \
--provider file \
--serp-source tests/fixtures/duckduckgo_search_results.html \
--geo ua \
--language uk \
--device mobile \
--search-engine google \
--max-competitors 5 \
--max-core 10 \
--format textpython main.py analyze \
--site tests/fixtures/target_site.html \
--crawl-site \
--page-limit 3 \
--format textЭтот режим берёт seed page и анализирует ограниченное число внутренних ссылок.
python main.py analyze \
--site tests/fixtures/target_site.html \
--competitor tests/fixtures/competitor_agency.html \
--competitor tests/fixtures/competitor_content.html \
--llm-provider local \
--brief-audience "SEO manager" \
--max-core 8 \
--format textЕсли enrichment временно не нужен:
python main.py analyze \
--site tests/fixtures/target_site.html \
--competitor tests/fixtures/competitor_agency.html \
--llm-provider none \
--format jsonЕсли у тебя доступен Ollama-compatible endpoint:
python main.py analyze \
--site tests/fixtures/target_site.html \
--competitor tests/fixtures/competitor_agency.html \
--competitor tests/fixtures/competitor_content.html \
--llm-provider ollama \
--llm-model deepseek-v3.2:cloud \
--llm-host http://127.0.0.1:11434 \
--llm-timeout 250 \
--brief-audience "SEO manager" \
--max-core 8 \
--format textpython main.py analyze \
--site tests/fixtures/target_site.html \
--competitor tests/fixtures/competitor_agency.html \
--competitor tests/fixtures/competitor_content.html \
--llm-provider ollama \
--llm-model deepseek-v3.2:cloud \
--llm-host http://127.0.0.1:11434 \
--llm-timeout 250 \
--brief-audience "SEO manager" \
--max-core 8 \
--format jsonПримечания:
- если Ollama недоступен, приложение автоматически откатится на
localenrichment и добавит warning; - по умолчанию модель для Ollama:
deepseek-v3.2:cloud; - по умолчанию latency/timeout budget для Ollama:
250секунд; - для cloud/remote Ollama-compatible моделей можно отдельно увеличить
--llm-timeoutбез изменения основного HTTP timeout для страниц; - для
deepseek-v3.2:cloudзапросы отправляются сthink=false, task-aware prompt versions (phase3-v3/*) и automatic retry при invalid/truncated JSON; - также поддерживаются переменные окружения
OLLAMA_HOSTиOLLAMA_MODEL.
Реально проверенный smoke test на этой машине (2026-04-05):
- endpoint
http://127.0.0.1:11434доступен; - модель
deepseek-v3.2:cloudустановлена; - команда выше успешно вернула structured Phase 3 output без fallback warnings;
- в live output были подтверждены
niche_summary,opportunity_scores,gap_explanations,page_recommendationsиcontent_brief.
Запуск API-сервера:
python main.py serve \
--host 127.0.0.1 \
--port 8000 \
--artifacts-dir dataКлючевые endpoints:
GET /healthGET /api/v1/jobsPOST /api/v1/jobs/analyzePOST /api/v1/jobs/searchGET /api/v1/jobs/{job_id}GET /api/v1/jobs/{job_id}/resultGET /api/v1/jobs/{job_id}/artifactsGET /api/v1/jobs/{job_id}/artifacts/{artifact_name}
Пример создания analyze job:
curl -X POST "http://127.0.0.1:8000/api/v1/jobs/analyze" \
-H "Content-Type: application/json" \
-d '{
"target_source": "tests/fixtures/target_site.html",
"competitor_sources": ["tests/fixtures/competitor_agency.html"],
"llm_provider_name": "none",
"max_core_terms": 8
}'Пример создания search job:
curl -X POST "http://127.0.0.1:8000/api/v1/jobs/search" \
-H "Content-Type: application/json" \
-d '{
"query": "купить машину украина",
"limit": 2,
"preserve_limit": 3,
"provider": "file",
"serp_source": "tests/fixtures/duckduckgo_search_results.html"
}'Artifacts сохраняются в каталоге, указанном через --artifacts-dir, в структуре:
data/
├── jobs/
│ └── <job_id>.json
└── artifacts/
└── <job_id>/
├── <website>_analysis_<date>.json
├── <website>_analysis_<date>.txt
├── <website>_analysis_<date>.md
└── <website>_analysis_<date>.csv
Файл serp_results.json должен содержать массив строк или объектов с полем url, domain или source.
Пример:
[
"https://example.com",
{ "url": "https://competitor.example" },
{ "source": "tests/fixtures/competitor_agency.html" }
]CLI возвращает:
niche_hypotheses— 2–3 гипотезы нишиtarget— on-page SEO сигналы целевой страницыsearch_result— SERP context и preserved/primary results при--querycompetitors— анализ пересечений и gaps по конкурентамcrawled_pages— дополнительные страницы target site при--crawl-siteniche_summary— краткое резюме ниши и evidence bandopportunity_scores— score/label/explanation по возможностямgap_explanations— объяснения content gaps по конкурентамpage_recommendations— рекомендации по типу страницы и кластеруcluster_bundles— сгруппированные кластеры термовcontent_brief— draft брифа для контентаseo_core— итоговое SEO-ядро с полями:termclusterintentprioritysourcecompetitor_counttarget_scorecompetitor_scoresupporting_termsrationale
Это Phase 4 backend MVP с CLI и API, а не финальный production SEO engine. Он полезен для:
- прототипирования пайплайна
- проверки формата результата
- быстрой локальной проверки HTML-страниц
- query-driven competitor discovery
- черновой генерации priorities, page recommendations и content briefs
- фонового запуска анализов через jobs API
- экспорта артефактов в несколько форматов
- подготовки к следующему этапу: PostgreSQL / Redis / dashboard / scheduled jobs
См. SOW.md, ARCHITECTURE.md и TODO.md.