ai-seo-analyzer / docs /FULL_FUNCTIONAL_DOCUMENTATION.md
lsdf's picture
Apply local-first accumulation for chunk-level optimizer progress.
f65551f
|
raw
history blame
29.9 kB
# SEO AI Editor — исчерпывающая документация функционала, логики и алгоритмики
Документ описывает приложение как инженерную спецификацию: что делает каждый модуль, какие данные принимает и возвращает, какие формулы использует, какие ограничения применяет и как воспроизвести поведение системы без чтения исходного кода.
---
## 1) Концепция приложения
`SEO AI Editor` объединяет два аналитических контура и один контур улучшения текста:
1. **SEO-контур** (`POST /analyze`)
- Word Count (total/significant)
- N-gram анализ (1..4)
- BM25-рекомендации (`add/remove/ok`)
- BERT-семантика по ключам
- Title-анализ (length/ngrams/coverage/BERT)
2. **Semantic Core** (`POST /api/v1/semantic/analyze`, `POST /api/v1/semantic/search`)
- NLP-разбор и лемматизация
- семантический граф (слова + фразы)
- веса узлов и связей в шкале `1..100`
- гипертекстовая разметка
- реферат
- смысловой поиск по словам и фразам
- сравнение с конкурентами (включая таблицу мощных терминов)
3. **LLM Optimizer** (`POST /api/v1/optimizer/run`)
- итеративная локальная оптимизация текста
- многокритериальный скоринг с защитой от деградации
- каскад уровней правок (от минимальных к более широким)
- детализированный debug-лог по кандидатам
---
## 2) Архитектура и ответственность файлов
- `app.py` — FastAPI оркестратор, endpoint-ы, связывание модулей.
- `models.py` — Pydantic-модели входов/выходов.
- `logic.py` — SEO-ядро: токены, n-grams, BM25, BERT, Title.
- `nlp_processor.py` — NLP-предобработка для semantic-контура.
- `semantic_graph.py` — построение графа и вычисление смысловых весов.
- `highlighter.py` — разметка текста по semantic-весам.
- `summarizer.py` — генерация реферата.
- `search.py` — смысловой поиск в графе (фразы + слова).
- `url_fetcher.py` — извлечение текста/title из URL с выбором user-agent.
- `optimizer.py` — LLM-оптимизация с обратной связью от метрик.
- `templates/index.html` — frontend (UI + клиентская логика JS).
---
## 3) Поддерживаемые языки
Поддерживаемые языки анализа:
- `ru`, `en`, `de`, `es`, `it`, `pl`, `pt`
Языки задаются кодом и сопоставляются с spaCy-моделями в `logic.py` (`MODEL_NAMES`).
---
## 4) Backend API и контракты
## 4.1 `POST /analyze`
### Назначение
Комплексный SEO-анализ target-текста относительно конкурентов и ключевых фраз.
### Вход (`AnalysisRequest`)
- `target_text: str`
- `competitors: List[str]`
- `keywords: List[str]`
- `language: str`
- `target_title: str`
- `competitor_titles: List[str]`
### Выход (`AnalysisResponse`)
- `ngram_stats`
- `bm25_recommendations`
- `bert_analysis`
- `word_counts`
- `title_analysis`
### Оркестрация в `app.py`
1. Word counts (`count_words`) для target и каждого competitor.
2. N-gram статистика (`calculate_ngram_stats`).
3. Нормализация ключей (`parse_keywords`) и BM25 (`calculate_bm25_recommendations`).
4. BERT-анализ (`perform_bert_analysis`).
5. Title-анализ (`analyze_title`) если `target_title` не пустой.
---
## 4.2 `POST /api/v1/semantic/analyze`
### Назначение
Построение semantic-среза по target и конкурентам.
### Вход (`SemanticAnalyzeRequest`)
- `text: str`
- `competitors: List[str]`
- `language: str`
- `threshold: int` (порог подсветки)
- `compression_ratio: float` (доля предложений в реферате)
### Выход (`SemanticAnalyzeResponse`)
- `target`:
- `graph` (`nodes`, `links`)
- `markup_text`
- `summary`
- `top_keywords`
- `word_weights`
- `stats`
- `competitors[]`: тот же формат
- `comparison`:
- `target_nodes`, `target_links`
- `avg_comp_nodes`, `avg_comp_links`
- `num_competitors`
- `term_power_table`
### Логика таблицы `term_power_table`
Для каждого термина из объединения target + competitors:
- `target_weight`
- `competitor_avg_weight`
- `competitor_weights` (`K1..Kn`)
- `comp_occurrence` (`X` в `X/Y`)
- `comp_total` (`Y`)
- `term_type` (`word` или `phrase`)
---
## 4.3 `POST /api/v1/semantic/search`
### Назначение
Смысловой поиск по документу через граф.
### Вход (`SemanticSearchRequest`)
- `query_text`
- `text`
- `language`
- `top_n`
### Выход (`SemanticSearchResponse`)
- `results[]`: `lemma`, `score (1..100)`, `type (word|phrase)`
---
## 4.4 URL Import API
### `GET /api/v1/url/user-agents`
Возвращает список пресетов user-agent для выбора в UI.
### `POST /api/v1/url/fetch`
Извлекает `title` и основной `text` страницы:
- вход: `url`, `user_agent`, `timeout_seconds`
- выход: `ok`, `status_code`, `title`, `text`, `error`, `final_url`, agent-метаданные.
Обработка ошибок не ломает UI: endpoint возвращает `ok=false` и `error`.
---
## 4.5 `POST /api/v1/optimizer/run`
### Назначение
Итеративная локальная дооптимизация target-текста через LLM.
### Вход (`OptimizerRequest`)
- аналитические данные: `target_text`, `competitors`, `keywords`, `language`, `target_title`, `competitor_titles`
- LLM: `api_key`, `api_base_url`, `model`, `temperature`
- стратегия: `max_iterations`, `candidates_per_iteration`, `optimization_mode`
### Выход (`OptimizerResponse`)
- `optimized_text`
- `baseline_metrics`, `final_metrics`
- `iterations[]` (подробный лог шагов)
- `applied_changes`
- `optimization_mode`
- `error` (если есть)
---
## 5) Подробная алгоритмика по модулям
## 5.1 `logic.py` — SEO-ядро
### `load_model_if_missing(lang)`
Ленивая загрузка spaCy-модели конкретного языка. Цель: не загружать все модели на старте (критично для HF ресурсов).
### `load_models()`
Служебная массовая загрузка моделей (используется ограниченно; основной путь в проде — lazy).
### `get_doc(text, lang)`
Единая точка получения spaCy `Doc` с предобработкой языка/модели.
### `is_valid_token(t)`
Фильтр значимых токенов (исключает шумовые категории: punctuation/space/часть stop и др.).
### `get_lemmas_flat(text, lang)`
Плоский список лемм значимых токенов. Базовый строительный блок для метрик.
### `generate_ngrams_safe(text, lang, n)` — Smart Window
Ключевой принцип:
- размер окна задается по **значимым** словам;
- stop-слова внутри валидного окна могут сохраняться для естественных фраз;
- символные границы (punct/num/sym) не дают сшивать ложные фразы.
Это гарантирует более естественные n-grams и согласованность между разными подсистемами.
### `count_words(text, lang)`
Возвращает:
- `total` — количество словоформ
- `significant` — количество значимых токенов после фильтра
### `calculate_ngram_stats(target_text, competitor_texts, lang)`
Строит частотные словари 1..4-грамм, агрегирует:
- частоты target
- средние частоты competitors
- сигналы дефицита/избытка
- детализацию по каждому конкуренту (для интерфейсных таблиц)
### `parse_keywords(raw_phrases, lang)`
Нормализует сырые ключи пользователя в:
- фразовые ключи
- униграммы
с учетом текущего языка и лемматизации.
### `calculate_bm25_recommendations(...)` — Mirror Principle
BM25 использует тот же подход токенизации/фразогенерации, что и n-gram ядро.
Смысл:
- сравнить релевантность target и среднего competitor-профиля по тем же термам;
- выдать действие:
- `add` — недобор терма,
- `remove` — вероятный переспам,
- `ok` — баланс.
### `get_bert_model()`
Ленивая инициализация sentence-transformers модели.
### `perform_bert_analysis(target_text, competitor_texts, key_phrases, lang)`
Для каждой ключевой фразы:
- ищет наиболее близкие чанки текста;
- считает similarity для target и competitors;
- формирует детализацию (`my_max_score`, competitor-сравнение, статусы).
### `analyze_title(target_title, competitor_titles, raw_keywords, lang)`
Оркестратор Title-пайплайна:
- `_title_length`
- `_title_ngrams`
- `_title_keyword_coverage`
- `_title_bert`
#### `_title_length(...)`
Сравнивает длину target title с конкурентным диапазоном/средним.
#### `_title_ngrams(...)`
N-gram сопоставление title-уровня.
#### `_title_keyword_coverage(...)`
Проверяет покрытие пользовательских ключей в target и competitor title.
#### `_title_bert(...)`
Оценивает semantic-близость title к ключевому набору.
---
## 5.2 `nlp_processor.py`
### `preprocess_text(text, lang)`
Преобразует текст в структуру предложений:
- `raw_text`
- `tokens[]` с полями `text`, `whitespace`, `lemma`, `is_significant`, `is_punct`, `is_space`
- `lemmas_clean` (очищенный список лемм)
Критично: сохранение `whitespace` и исходных токенов позволяет восстановить текст UI-послойно без потери форматирования.
---
## 5.3 `semantic_graph.py` — математическое ядро
### `_normalize_to_1_100(values)`
Нормализация произвольных весов в целочисленную шкалу `1..100`.
### `_extract_significant_lemmas(sent)`
Достает значимые леммы из предложения.
### `_is_noise_sentence(text)`
Отбрасывает шумовые фрагменты (короткие CTA, boilerplate-паттерны).
### `_canonicalize_term(term)`
Rule-based каноникализация термов (снижение дублей и вариативности).
### `_extract_phrase_candidates(sentence_text, lang)`
Извлечение кандидатных фраз через `generate_ngrams_safe` и фильтры.
### `_normalize_lemma_sequence(lemmas)`
Нормализация последовательностей лемм для устранения артефактов.
### `build_semantic_graph(sentences_data, lang)`
Базовые шаги:
1. Сформировать множество терминов (слова + фразы).
2. Подсчитать частоты терминов и совместные появления.
3. Построить направленный граф.
4. Рассчитать вес ребра:
- `P(B|A) = cooc(A,B) / occ(A) * 100`
- затем ограничение в `0..100`.
5. Рассчитать важность узлов:
- PageRank как глобальная связность,
- termness/coverage корректировки,
- штрафы для слишком общих доменных токенов.
6. Вернуть граф и карту `word_weights`.
### `get_graph_data_for_frontend(graph, top_edges_per_node=8)`
Сериализует `networkx` граф в плоский JSON:
- `nodes[]`
- `links[]`
с ограничением числа ребер на узел для управляемого рендера.
### `get_top_keywords(node_weights, top_n=20)`
Возвращает top-N терминов по весу.
---
## 5.4 `highlighter.py`
### `generate_markup_for_frontend(sentences_data, word_weights, threshold=50)`
Маркирует важные блоки:
- если вес леммы/фразы >= порога, блок становится `is_link=true`;
- соседние значимые токены могут объединяться в один кликабельный сегмент;
- возвращается структура, удобная для реактивного рендера в UI.
---
## 5.5 `summarizer.py`
### `generate_summary(sentences_data, word_weights, compression_ratio)`
Скоринг предложения:
- `score = sum(weight(unique_lemmas)) / sqrt(token_count)`
Далее:
1. сортировка по score убыв.
2. выбор top по `compression_ratio`
3. восстановление хронологического порядка для читабельности.
---
## 5.6 `search.py`
### `_normalize_query_text(text)`
Нормализует запрос для устойчивого поиска.
### `semantic_search(query_text, G, word_weights, language, top_n)`
Алгоритм:
1. Нормализовать и лемматизировать запрос.
2. Приоритетно проверить фразы (tri/bi) из запроса.
3. Fallback на слова.
4. Для найденных точек входа добавить соседей по графу.
5. Собрать score из силы связи и веса узла.
6. Нормализовать score в `1..100`.
7. Вернуть top-N и тип (`phrase`/`word`).
---
## 5.7 `url_fetcher.py`
### `get_user_agent_presets()`
Возвращает список пресетов (Googlebot, Bingbot, ChatGPT user-agent, GPTBot, Chrome Desktop и др.).
### `_normalize_whitespace(text)`
Схлопывает лишние пробелы/переводы строк.
### `_normalize_url(url)`
Приводит URL к валидному виду (схема, trimming).
### `_resolve_user_agent(user_agent_key)`
По ключу выбирает фактическую строку user-agent.
### `_extract_main_text_and_title(html)`
HTML extraction pipeline:
- удалить `script/style/noscript/nav/footer/header/form/svg` и прочий boilerplate;
- приоритетно извлекать `article/main`;
- fallback на абзацы/списки;
- final fallback на `body` текст;
- вернуть очищенный `title` и основной `text`.
### `fetch_url_content(url, user_agent_key, timeout_seconds)`
Выполняет HTTP-запрос и возвращает структурированный результат для UI/API.
---
## 5.8 `optimizer.py` — LLM-оптимизация текста
### Цель модуля
Итеративно улучшать конкретные проблемные зоны из аналитики, избегая полной перегенерации текста и сохраняя стиль/повествование.
### Служебные функции подготовки
- `_tokenize` — токенизация строки.
- `_filter_stopwords` — удаление stop-слов.
- `_split_sentences` — сегментация на предложения.
- `_max_sentences_for_level` — лимиты длины кандидата по каскаду.
- `_validate_candidate_text` — pre-check качества (пустота, дубль слова/сущности, подозрительные токен-склейки, превышение лимита предложений).
### Снимки аналитики
- `_build_analysis_snapshot` — пересчет `/analyze` локально.
- `_build_semantic_snapshot` — пересчет semantic среза локально.
### Скоринг и выбор цели
- `_compute_metrics` — единый набор метрик состояния:
- composite score
- `bert_low_count`
- `bert_phrase_scores`
- `bm25_remove_count`
- сигналы n-gram/semantic
- `title_bert_score`
- `semantic_gap_count`, `semantic_gap_sum`, `semantic_gap_terms`
- `_choose_optimization_goal` — выбирает приоритетную проблему.
- для BERT-целей используется порог `BERT_TARGET_THRESHOLD=0.7` (допустимый рабочий минимум может быть снижен до `0.65`), без конкурентного override;
- `_choose_sentence_idx` — выбирает релевантный чанк для правки.
### Параметры Semantic Gap в оптимизаторе
- `SEMANTIC_GAP_TOLERANCE_PCT = 0.15` — допускается отклонение до ~15% от target, без штрафа.
- `SEMANTIC_GAP_MIN_ABS = 3.0` — игнорируются микрошумы с маленькой абсолютной разницей.
- Gap считается значимым, если одновременно:
- `competitor_avg_weight > target_weight * (1 + tolerance)`
- `competitor_avg_weight - target_weight >= min_abs`
Это убирает пере-жесткую подгонку к среднему конкуренту и снижает ложные колебания `semantic_gap_count`.
### Генерация кандидатов
- `_llm_edit_chunk` — отправляет structured prompt в OpenAI-compatible API.
- учитывает `cascade_level` и тип операции (`rewrite`/`insert`)
- явно требует грамматически корректный и естественный текст
- ограничивает число предложений по уровню
### Применение правок
- `_replace_span` — замена диапазона предложений.
- `_insert_after` — вставка после диапазона.
### Принятие/отклонение кандидата
- `_goal_improved`:
- для BERT: улучшение score целевой фразы минимум на `BERT_GOAL_DELTA_MIN=0.005` **или** снижение `bert_low_count`;
- для других целей: профильные метрики улучшения.
- `_is_candidate_valid`:
- hard constraints (не ухудшать критичные метрики сверх допустимого);
- режимы `conservative/balanced/aggressive` задают пороги регрессии;
- решение учитывает и `goal_improved`, и общий `delta_score`.
### Главная функция `optimize_text`
Итерационный цикл:
1. baseline metrics.
2. выбрать goal.
3. выбрать пул чанков и операцию каскада.
- на шаг выбирается несколько span-кандидатов (multi-chunk selection), а не один;
- ранжирование учитывает `focus_terms/avoid_terms`, chunk-level relevance и шумовые эвристики (menu/CTA/header penalties);
- используется `attempt_cursor` по цели и `attempted_spans`, чтобы избежать циклов по одному и тому же участку.
4. сгенерировать `N` кандидатов для каждого выбранного span.
5. pre-validation (формат/качество/длины).
6. chunk-level оценка:
- вычисляется `chunk_goal_delta` (релевантность чанка до/после к текущей цели);
- кандидат помечается `local_chunk_improved`, если прирост выше порога цели.
7. document-level оценка:
- полный пересчет метрик для всего текста;
- проверка глобальных ограничений через `_is_candidate_valid`.
8. staged acceptance:
- если кандидат улучшает цель/общий score и проходит глобальные ограничения — `applied`;
- если локально улучшает чанк, но глобально не проходит — кандидат кладется в queue.
- для BERT учитывается прямой документный `bert_phrase_delta` по целевой фразе: даже небольшой положительный рост считается полезным шагом при отсутствии регрессий по guardrails.
- если нет `promotable` кандидата, но есть guardrail-valid кандидат с `local_chunk_improved`, применяется режим `applied_local_progress`: правка принимается локально и оптимизация переходит к следующему чанку (накопительная стратегия).
9. batch-логика queue:
- optimizer пробует совместно применить комбинации из 2..4 локально сильных не конфликтующих правок;
- batch принимается только при прохождении глобальных ограничений и положительном совокупном локальном приросте.
10. при серии неудач эскалировать каскад (`L1 -> L2 -> L3 -> L4`), при успехе сбрасывать на `L1`.
- `L1`: локальный rewrite (обычно 1 предложение),
- `L2`: rewrite расширенного окна (2-3 предложения, несколько вариантов радиусов),
- `L3`: insert bridge (вставка) с возможным fallback на rewrite,
- `L4`: более широкий rewrite окна (до 5 предложений с вариативным охватом).
11. вести подробный лог по каждому кандидату.
- в debug-таблице фиксируются и chunk-level сигналы (`local+`, `chunk Δ`, `rel before->after`) наряду с глобальными (`Δ score`, `valid`, `goal+`);
- для каждого кандидата сохраняется `llm_prompt_debug` (операция, цель, фокус-термы, chunk и ближайший контекст), что позволяет анализировать фактический вход в LLM.
- также сохраняется `metrics_delta` (вклад BM25/BERT/Semantic/N-gram/Title в общий сдвиг), включая `semantic_gap_sum` и изменение состава gap-термов (`semantic_gap_terms_added/removed`), чтобы видеть, за счет чего падает или растет `score`.
---
## 6) Frontend (`templates/index.html`) — сценарии и функции
## 6.1 Ввод данных и URL import
- `loadUserAgentOptions` — загрузка пресетов UA.
- `fetchUrlPayload` — запрос к URL API.
- `fetchTargetFromUrl` — заполнение target text/title из URL.
- `fetchCompetitorsFromUrls` — массовое заполнение competitors.
Ручной ввод всегда остается рабочим fallback-сценарием.
## 6.2 Локальное сохранение проекта
- `saveProject` — экспорт JSON.
- `loadProject` — загрузка JSON.
- `applyProjectData` — восстановление полей и результатов.
- `clearProject` — новый проект/сброс.
API-ключ оптимизатора в persist-состояние не сохраняется.
## 6.3 Запуск аналитики и отрисовка
- `runAnalysis`
- `runSemanticAnalysis`
- `runSemanticSearch`
- `renderResults`
- `renderSemanticResults`
- `renderTitleResults`
- `showNgramTable`
## 6.4 Сводка и оптимизатор
- `renderActionSummary` — агрегирует рекомендации BERT/BM25/N-grams/Title/Semantic в табличный формат.
- `runLlmOptimization` — запуск оптимизации.
- `renderOptimizerResults` — итог и debug-лог по шагам/кандидатам.
- `applyOptimizedText` — перенос optimized текста в `target_text`.
## 6.5 Сортировка таблицы мощных терминов
- `setSemanticTermSortBy`
- `toggleSemanticTermSortDir`
Поддерживаются сортировки по:
- `Мой вес`
- `Avg K`
- `Freq (X/Y)` (с приоритетом большего `X` при одинаковом `Y`)
---
## 7) Данные и модели (`models.py`)
Ключевые модели:
- `AnalysisRequest`, `AnalysisResponse`
- `SemanticAnalyzeRequest`, `SemanticAnalyzeResponse`
- `SemanticSearchRequest`, `SemanticSearchResponse`
- `UrlFetchRequest`, `UrlFetchResponse`, `UserAgentInfo`, `UserAgentsResponse`
- `OptimizerRequest`, `OptimizerResponse`
Роль моделей:
- жестко фиксируют API-контракты;
- упрощают валидацию;
- создают стабильный интерфейс между frontend/backend.
---
## 8) Практические вычислительные принципы
1. **Согласованная нормализация**
Одни и те же правила токенизации/лемматизации используются в нескольких модулях, чтобы избежать рассинхронизации метрик.
2. **Локальные правки вместо полной перегенерации**
Оптимизатор меняет только локальные участки текста и проверяет эффект после каждой правки.
3. **Многокритериальная защита**
Кандидат не принимается, если улучшение одной метрики достигается ценой неприемлемой деградации других.
4. **Объяснимость**
Подробный лог итераций фиксирует baseline шага, кандидатов, причины отклонения и примененный вариант.
---
## 9) Рекомендации по воспроизведению приложения по документации
Минимальный путь воспроизведения:
1. Поднять FastAPI-приложение с endpoint-ами из раздела 4.
2. Реализовать `logic.py` и `semantic_*` модули с описанными формулами и пайплайнами.
3. Сделать frontend с соответствующими сценариями (`runAnalysis`, `runSemanticAnalysis`, `runLlmOptimization`).
4. Добавить URL extractor и LLM optimizer как отдельные backend сервисы.
5. Проверить контракты ответов, чтобы UI-таблицы и вкладки заполнялись без адаптеров.
---
## 10) Эксплуатация и деплой (Hugging Face)
- Рекомендуемый режим: lazy загрузка моделей.
- При проблемах типа `Could not resolve host: huggingface.co` рассматривать как внешнюю инфраструктурную проблему DNS/egress.
- Для диагностики сверять:
- `repo_sha` и `runtime_sha`
- `runtime_stage`
- При зависании сборки использовать повторный trigger-build.
---
## 11) Smoke-check после любых изменений
1. `python -m py_compile app.py logic.py semantic_graph.py search.py optimizer.py url_fetcher.py`
2. Проверка endpoint-ов:
- `/analyze`
- `/api/v1/semantic/analyze`
- `/api/v1/semantic/search`
- `/api/v1/url/user-agents`
- `/api/v1/url/fetch`
- `/api/v1/optimizer/run`
3. Проверка UI:
- табы рендерятся;
- сортировки и таблицы работают;
- URL import заполняет text/title;
- save/load/new project работают;
- оптимизатор пишет лог и применяет текст.