# 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` или в UI — SSE `run-stream`) - итеративная локальная оптимизация текста - многокритериальный скоринг с защитой от деградации - каскад уровней правок (от минимальных к более широким) - детализированный 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-оптимизация с обратной связью от метрик. - `docs/TEXT_OPTIMIZER_PRINCIPLES.md` — живой регламент принципов оптимизатора (stage-пайплайн, допуски, guardrails). - `templates/index.html` — разметка UI. - `static/js/app.js` — вся клиентская логика (подключается как `/static/js/app.js`; без гигантского inline-скрипта — см. `docs/HF_SES_AND_UI.md`). --- ## 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`, `phrase_strategy_mode`, `bert_stage_target` - `phrase_strategy_mode`: `auto | distributed_preferred | exact_preferred | ensemble` - `ensemble`: в пределах итерации циклически пробует несколько phrase-стратегий и ранжирует кандидаты общей utility-функцией. - `bert_stage_target`: пользовательский порог завершения этапа A (BERT), например `0.61` вместо `0.70`. ### Выход (`OptimizerResponse`) - `optimized_text` — итоговый body (target) - `optimized_title` — итоговая строка для поля **Title**; в ответе она берётся из снимка `title_analysis.target_title` (тот же текст, что учитывался в метрике Title BERT), с запасным вариантом из переменной оптимизатора. В `final_metrics` дополнительно есть `resolved_title` с тем же смыслом (удобно для UI/fallback). - `baseline_metrics`, `final_metrics` - `iterations[]` (подробный лог шагов) - `applied_changes` - `optimization_mode` - `phrase_strategy_mode` - `bert_stage_target` - `stopped_early`, `stop_reason` — при ручной остановке (частичный результат) - `error` (если есть) ### `POST /api/v1/optimizer/run-stream` (SSE) Тело как у `run`. Поток `text/event-stream`, события `job` (с `job_id`), `preparing`, `started`, `step_start`, `llm_call`, затем `complete` с полем `result` или `error`. ### `POST /api/v1/optimizer/cancel` Тело: `{"job_id": "..."}`. Только флаг отмены; клиент дочитывает SSE до `complete`. ### UI и HF/SES Клиентский код: **`static/js/app.js`** + `GET /static/js/app.js`. Прогресс оптимизатора — **локальная панель с текстовым логом** (и тонкая полоса), **без** `#loader`. Подробности про SES и «мёртвые кнопки»: `docs/HF_SES_AND_UI.md`. --- ## 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. - роль модели в prompt: **semantic-vector optimizer for SEO**, а не общий “copy editor”. - учитывает `cascade_level` и тип операции (`rewrite`/`insert`) - явно требует грамматически корректный и естественный текст - ограничивает число предложений по уровню - для BERT динамически выбирает стратегию по длине целевой фразы: - короткие цели: допустим один natural exact match; - длинные multi-word цели: приоритет у distributed semantic coverage (части фразы/леммы/близкие формулировки), без forced exact match. - exact phrase не должен повторяться: при неестественном звучании он запрещается в пользу распределённой формулировки. - для `rewrite` явно требует сохранить исходный смысл `sentence-by-sentence` и не менять субъект/ключевую сущность без необходимости. ### Применение правок - `_replace_span` — замена диапазона предложений. - `_insert_after` — вставка после диапазона. ### Принятие/отклонение кандидата - `_goal_improved`: - для BERT: улучшение score целевой фразы минимум на `BERT_GOAL_DELTA_MIN=0.005` **или** снижение `bert_low_count`; - для других целей: профильные метрики улучшения. - `_candidate_utility`: - многоцелевая функция полезности кандидата с динамическими весами; - учитывает одновременно `bert_phrase_delta`, `chunk_goal_delta`, `score_delta`; - добавляет мягкие штрафы за регрессии по BM25/BERT-low/N-gram/SemanticGap/Title; - в BERT-push режиме (когда фраза ниже порога) усиливает вес phrase-level прогресса. - `_is_candidate_valid`: - hard constraints (не ухудшать критичные метрики сверх допустимого); - режимы `conservative/balanced/aggressive` задают пороги регрессии; - решение учитывает и `goal_improved`, и общий `delta_score`. - `_is_stage_complete` для `bert`: - этап считается завершённым только когда **каждая** отслеживаемая ключевая фраза достигает `bert_stage_target` (проверка по `min(bert_phrase_scores)`); - достижение порога одной «сильной» фразой больше не завершает BERT-этап. - унифицированный цикл по целям: базовые параметры запроса `max_iterations` и `candidates_per_iteration` задают «якорь», но для **каждой** цели вычисляется эффективный бюджет (`_per_goal_budget`): число попыток и ширина пула кандидатов **масштабируются по дефициту** до таргета — для BERT по разрыву score до порога, для semantic по `semantic_gap`, для n-gram по отставанию/перегрузу относительно целевого счётчика, для BM25 по «лишним» вхождениям слова, для title по разрыву `title_bert_score`. После исчерпания лимита по текущей цели оптимизатор переходит к следующей цели той же стадии. - `_validate_candidate_text`: - отклоняет некачественные/спамные кандидаты (дубли слов/сущностей, подозрительные склейки токенов); - добавляет anti-stuffing фильтр для цели BERT (повторы exact phrase и чрезмерные повторы focus-термов). ### Главная функция `optimize_text` Итерационный цикл: 1. baseline metrics. - общий бюджет шагов оценивается как **сумма эффективных итераций по всем целям** (`_estimate_total_loop_budget`: для каждой цели — `_per_goal_budget`, затем сумма по стадиям с верхней отсечкой), то есть масштабируется и по числу целей, и по величине отставания от таргета. В SSE-событии `step_start` дополнительно передаются `goal_budget_iter` и `goal_budget_candidates` для текущей цели. 2. выбрать goal. 3. выбрать пул чанков и операцию каскада. - **Этап `title`:** если средняя BERT-близость Title к ключам (`title_bert_score`) ниже порога (`TITLE_TARGET_THRESHOLD` ≈ 0.65), цель — **только переписать текст из поля Title** (`target_title`), а не абзац основного текста. LLM получает текущий title, выдержку из body и ключевые слова; метрики пересчитываются с новым title. Пакетные правки по body с title не смешиваются. - **Проверка деплоя:** в debug кандидата для шага `title` в `llm_prompt_debug` должно быть `"operation": "title_rewrite"`, а `chunk_text` — короткая строка текущего Title. Если видите `"operation": "rewrite"` и длинный `chunk_text` из body — на сервере старая версия `optimizer.py` (или не пересобран образ). - на шаг выбирается несколько span-кандидатов (multi-chunk selection), а не один; - ранжирование учитывает `focus_terms/avoid_terms`, chunk-level relevance и шумовые эвристики (menu/CTA/header penalties); - для **n-gram** целей предложения ранжируются через **скользящие перекрывающиеся окна** из 2–4 предложений (шаг 1): каждому предложению присваивается лучший балл среди окон, оценка штрафует локальные повторы фразы и шумовые блоки; - для BERT-целей ранжирование не ограничивается участками с already-present вхождениями: дополнительно приоритизируются релевантные участки с недопредставленными core-термами, где их можно добавить естественно; - используется `attempt_cursor` по цели и `attempted_spans`, чтобы избежать циклов по одному и тому же участку. 4. сгенерировать `N` кандидатов для каждого выбранного span (`N` зависит от эффективного бюджета кандидатов для цели и каскада, см. `_per_goal_budget` и деление по 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`: правка принимается локально и оптимизация переходит к следующему чанку (накопительная стратегия). - ранжирование и выбор best-кандидата дополнительно учитывают `candidate_utility`, чтобы BERT-оптимизация не вредила следующим этапам по другим метрикам. 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; - LLM возвращает поле `rationale` (1 строка) — краткое объяснение, почему правка должна повысить релевантность цели. - также сохраняется `metrics_delta` (вклад BM25/BERT/Semantic/N-gram/Title в общий сдвиг), включая `semantic_gap_sum` и изменение состава gap-термов (`semantic_gap_terms_added/removed`), чтобы видеть, за счет чего падает или растет `score`. --- ## 6) Frontend (`templates/index.html` + `static/js/app.js`) ## 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` — `POST /api/v1/optimizer/run-stream` (SSE); локальная панель **лога** + тонкий progress bar; **без** `#loader`. - `requestStopOptimizer` — `POST /api/v1/optimizer/cancel`; поток дочитывается до `complete` (частичный результат). - `optimizerLogAppend` / `applyOptimizerStreamEvent` — текстовый ход работы. - `renderOptimizerResults` — итог и debug-лог; баннер при `stopped_early`. - `applyOptimizedText` — перенос optimized текста в `target_text`. - `nv(v, d)` — nullish-fallback без операторов `??` (SES на HF). ## 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 работают; - оптимизатор пишет лог и применяет текст.