docs+ui: страница «Документация», единый стиль заголовков, перевод на оператора
Добавлена /docs.html — обзор мультиагентной системы для оператора. Все термины в формате «русский (english)», жирным: ветка (intent), маршрутизатор (router), пошаговый сценарий (state machine), шаг (step), допустимые переходы (allowed_next), слоты (slots), условия выхода (exit conditions), переключение ветки (hard handoff), удержание в ветке (sticky state machine), структурированный ответ (structured output), отложенный сценарий (suspended/resume), защита от петли (routing loop guard), состояние диалога (thread state). Плюс пошаговая схема обработки реплики и резюме защитных механизмов. Ссылка «Документация» добавлена в шапку всех страниц. Унификация заголовков под стиль «Версии» в правом сайдбаре Настроек: убран uppercase, переход на 13px / var(--fg) / font-weight 600 / зажатый letter-spacing. Применилось к .col-head во всех колонках, .field label в редакторе, .section-header в списке веток, заголовкам столбцов на странице Отладки и заголовкам секций RAG-результата. Бейджи (АКТИВНАЯ, система) оставлены прежними — это статусные метки, не заголовки. Переименование ветки escalate_human для согласованности с русским UI: «Эскалация на оператора» → «Перевод на оператора», описание тоже. Точечная миграция при старте (intent_service.migrate_intent_copy) обновляет существующие записи в БД, только если поле в точности совпадает со старым значением — операторские правки не затираются. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,7 @@ SEED_INTENTS: list[dict] = [
|
||||
{"code": "price_question", "name": "Цены и ДМС", "description": "Вопросы про стоимость услуг, оплату, ДМС."},
|
||||
{"code": "medical_question", "name": "Медицинский вопрос", "description": "Симптомы, лекарства, диагноз — требует врача."},
|
||||
{"code": "general_info", "name": "Общая справка", "description": "Адрес, часы работы, как доехать, общие вопросы."},
|
||||
{"code": "escalate_human", "name": "Эскалация на оператора", "description": "Передача диалога живому оператору."},
|
||||
{"code": "escalate_human", "name": "Перевод на оператора", "description": "Перевод диалога на живого оператора."},
|
||||
{"code": ROUTER_INTENT_CODE, "name": "Маршрутизатор", "description": "Системная ветка: промпт классификатора намерений. Пациенту напрямую не отвечает."},
|
||||
]
|
||||
|
||||
@@ -81,3 +81,38 @@ async def ensure_seed_intents(session: AsyncSession) -> None:
|
||||
if added:
|
||||
await session.commit()
|
||||
logger.info("Seeded %d missing intents", added)
|
||||
|
||||
|
||||
# Точечные переименования: пользователь правит UI-копию, но в БД уже залит
|
||||
# старый сид. Применяем мягко — только если поле в точности совпадает со старым
|
||||
# значением (значит оператор не правил его сам).
|
||||
_INTENT_NAME_MIGRATIONS: list[dict] = [
|
||||
{
|
||||
"code": "escalate_human",
|
||||
"old_name": "Эскалация на оператора",
|
||||
"new_name": "Перевод на оператора",
|
||||
"old_description": "Передача диалога живому оператору.",
|
||||
"new_description": "Перевод диалога на живого оператора.",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
async def migrate_intent_copy(session: AsyncSession) -> None:
|
||||
"""Обновляет name/description у системных веток, если в БД лежит старый текст."""
|
||||
updated = 0
|
||||
for spec in _INTENT_NAME_MIGRATIONS:
|
||||
intent = await get_intent_by_code(session, spec["code"])
|
||||
if intent is None:
|
||||
continue
|
||||
changed = False
|
||||
if intent.name == spec["old_name"]:
|
||||
intent.name = spec["new_name"]
|
||||
changed = True
|
||||
if intent.description == spec["old_description"]:
|
||||
intent.description = spec["new_description"]
|
||||
changed = True
|
||||
if changed:
|
||||
updated += 1
|
||||
if updated:
|
||||
await session.commit()
|
||||
logger.info("Migrated copy for %d intent(s)", updated)
|
||||
|
||||
Reference in New Issue
Block a user