Spaces:
Sleeping
Sleeping
| title: Nodes UI Flow | |
| emoji: 🤖 | |
| colorFrom: blue | |
| colorTo: indigo | |
| sdk: docker | |
| app_port: 7860 | |
| pinned: false | |
| # Nodes UI Flow | |
| Визуальный редактор интерактивных AI-сценариев: сценарий собирается из нод, запускается пошагово, задает вопросы пользователю, сохраняет ответы в память, ветвится по смыслу и может отвечать по knowledge-файлам. | |
| Проект сейчас содержит пример для RosUpack 2026, но ноды сделаны универсальными: такой же граф можно собрать для другого стенда, продукта или процесса. | |
| ## Что внутри | |
| - React + React Flow интерфейс для сборки графов. | |
| - FastAPI backend для LLM-запросов, классификации, извлечения памяти и ответов по файлам. | |
| - Выбор LLM provider в настройках: Ollama или DeepInfra. | |
| - Перефразирование реплик ассистента при запуске нод, чтобы сценарий не звучал одинаково каждый раз. | |
| - `LLM Test` режим: LLM сама проходит сценарий, а evaluator проверяет вопросы и ответы ассистента. | |
| - Сохранение workflow в JSON. | |
| - Knowledge-файлы, привязанные к конкретной `Knowledge Answer` ноде. | |
| ## Быстрый запуск на Windows | |
| Ollama запускается отдельно вручную. | |
| ```bat | |
| start_interface.bat | |
| ``` | |
| Скрипт откроет два окна: | |
| - backend: `http://localhost:8000` | |
| - frontend: `http://localhost:5173` | |
| Остановить интерфейс можно закрытием этих двух окон. | |
| ## Ручной запуск | |
| Backend: | |
| ```powershell | |
| cd backend | |
| python -m venv .venv | |
| .\.venv\Scripts\activate | |
| pip install -r requirements.txt | |
| python main.py | |
| ``` | |
| Frontend: | |
| ```powershell | |
| npm install | |
| npm run dev | |
| ``` | |
| Production build: | |
| ```powershell | |
| npm run build | |
| ``` | |
| ## Структура проекта | |
| ```text | |
| backend/ FastAPI backend | |
| public/ frontend config and presets | |
| scenarios/ | |
| dialog/ markdown versions of scenario scripts | |
| knowledge/ curated knowledge bases for Knowledge Answer nodes | |
| source/ original source documents | |
| src/ React app, nodes and workflow runtime | |
| workflows/ saved workflow JSON graphs | |
| archive/ old or experimental workflow snapshots | |
| start_interface.bat one-click Windows launcher | |
| ``` | |
| Runtime/generated folders are intentionally ignored by git: | |
| ```text | |
| dist/ | |
| node_modules/ | |
| backend/.venv/ | |
| knowledge_contexts/ | |
| test_logs/ | |
| transcript_logs/ | |
| ``` | |
| ## Основной workflow | |
| Главный пример: | |
| ```text | |
| workflows/full_workflow.json | |
| ``` | |
| Knowledge base для него: | |
| ```text | |
| scenarios/knowledge/rosupack_2026_knowledge_base.md | |
| ``` | |
| В `Knowledge Answer` ноде путь к файлу сохраняется прямо в JSON workflow, поэтому граф можно открыть после clone и продолжить использовать без повторного upload, если файл лежит в репозитории. | |
| ## Как устроен интерактивный сценарий | |
| Типичный поток: | |
| ```text | |
| Question -> Save Memory -> Assistant Message -> Semantic Branch -> Question/Message/... -> Knowledge Answer -> Restart | |
| ``` | |
| Runtime идет до первой `Question`, показывает вопрос в нижней панели и ждет ответ пользователя. Ответ можно: | |
| - ввести руками; | |
| - сгенерировать кнопкой `LLM answer`; | |
| - включить `Auto LLM answer`, чтобы LLM отвечала сама на каждый новый вопрос. | |
| Если у ноды включена галочка `Перефразировать при запуске`, backend перед показом реплики отправит текст в выбранный LLM provider и вернет новую формулировку с тем же смыслом. В transcript и дальше по графу попадет именно показанная пользователю версия. | |
| ## LLM provider | |
| Provider выбирается в `Настройки`: | |
| - `Ollama` — локальный режим, backend обращается к `http://localhost:11434`. | |
| - `DeepInfra` — облачный OpenAI-compatible endpoint. | |
| Для DeepInfra в настройках появляется поле API key. Ключ сохраняется локально в `backend/.deepinfra_api_key`, этот файл игнорируется git. Если ключ уже сохранен, поле можно оставить пустым, чтобы не менять его. | |
| Thinking/reasoning в LLM-вызовах отключен: для Ollama backend отправляет `think: false`, для DeepInfra используется `reasoning_effort: none`. | |
| ## Основные типы портов | |
| Порты окрашиваются по типу/смыслу, а не по цвету ноды. | |
| - `turn` — объект одного шага диалога: вопрос, ответ и накопленный dialog. | |
| - `dialog` / `dialog-in` — история сообщений. | |
| - `question` — текст вопроса. | |
| - `answer` — текст ответа пользователя. | |
| - `string` — обычный текст. | |
| - `object` — структурированные данные. | |
| Один input может принимать несколько входящих связей. Это используется, когда несколько веток сходятся в общий блок, например в общий `Еще вопросы?`. | |
| ## Ключевые ноды | |
| ### Question | |
| Задает вопрос ассистента и ставит workflow на паузу до ответа пользователя. | |
| Используйте `turn` output, если дальше нужна вся пара вопрос/ответ. Используйте `dialog` или `dialog-in`, если важно сохранить историю реплик. | |
| Опция `Перефразировать при запуске` заставляет LLM переписать вопрос перед показом пользователю. | |
| ### Assistant Message | |
| Показывает реплику ассистента без ожидания пользовательского ответа. | |
| Подходит для коротких объяснений, переходов между ветками и финальных историй. | |
| Опция `Перефразировать при запуске` работает так же, как в `Question`: смысл сохраняется, формулировка может меняться. | |
| ### Save Memory | |
| Извлекает значение из ответа пользователя и сохраняет его в память прогона. | |
| Пример ключей: | |
| ```text | |
| name | |
| role | |
| industry | |
| scale | |
| ``` | |
| Значения доступны в шаблонах через фигурные скобки: | |
| ```text | |
| {name}, хотели бы узнать что-то еще? | |
| ``` | |
| Если перед `Save Memory` был retry-переспрос, нода берет последний ответ пользователя из `dialog-in`, а не старый первый ответ из `turn`. Это важно для сценариев вроде проверки имени: пользователь может сначала ответить бессмыслицу, затем назвать имя, и в `{name}` сохранится именно последний корректный ответ. | |
| ### Semantic Branch | |
| LLM выбирает один выход по смыслу ответа пользователя. | |
| Один choice = один output. Альтернативы внутри одного choice пишутся через точку с запятой: | |
| ```text | |
| да; хочу еще; давай; есть вопрос | |
| нет; хватит; вернуться в начало | |
| ``` | |
| Точка с запятой означает альтернативные формулировки, а не условие, что все фразы должны встретиться одновременно. | |
| Если ответ непонятен, `retry on unclear` может сразу переспросить пользователя на этой же точке сценария. | |
| У retry-вопроса есть отдельная галочка `Перефразировать unclear-вопрос`, чтобы повторный вопрос звучал живее при нескольких неудачных ответах подряд. | |
| ### Knowledge Answer | |
| Отвечает на вопрос пользователя по файлу, привязанному к конкретной ноде. | |
| Поддерживаются: | |
| - `.md` | |
| - `.txt` | |
| - `.docx` | |
| - `.doc` как best-effort text extraction | |
| При upload backend сохраняет оригинал и extracted text. Для репозиторных сценариев лучше хранить curated `.md` knowledge base в `scenarios/knowledge/` и указывать этот относительный путь в `contextPath`. | |
| ### Restart | |
| Перезапускает интерактивный сценарий с начала. | |
| Удобно для выставочного сценария: если пользователь больше не хочет задавать вопросы, можно вернуть ассистента в стартовое состояние. | |
| ### Request to LLM | |
| Отправляет `system` и `user` prompt на backend. | |
| Используйте для универсальных LLM-операций, которые не покрыты готовыми специализированными нодами. | |
| ### Component | |
| Сворачивает часть графа во вложенный компонент. | |
| Подходит для повторяющихся блоков, когда сценарий начинает разрастаться. | |
| ## Как соединять ноды | |
| ### Сохранить имя | |
| ```text | |
| Question(turn) -> Semantic Branch(turn) | |
| Question(turn) -> Save Memory(turn) | |
| Semantic Branch(has-name) -> Save Memory(dialog-in) | |
| Save Memory(dialog) -> Assistant Message(dialog-in) | |
| ``` | |
| `Semantic Branch` проверяет, есть ли в ответе имя. Если ответа недостаточно, `retry on unclear` сразу переспросит. `Save Memory` получает старый `turn` и свежий `dialog-in`; приоритет отдается последнему ответу пользователя из `dialog-in`, поэтому после переспроса сохраняется корректное имя. | |
| ### Ветвление по смыслу | |
| ```text | |
| Question(turn) -> Semantic Branch(turn) | |
| Semantic Branch(choice A) -> Node A(dialog-in) | |
| Semantic Branch(choice B) -> Node B(dialog-in) | |
| Semantic Branch(unclear) -> retry или fallback | |
| ``` | |
| ### Общий финальный блок | |
| ```text | |
| Branch A final message(dialog) -> Shared Question(dialog-in) | |
| Branch B final message(dialog) -> Shared Question(dialog-in) | |
| Branch C final message(dialog) -> Shared Question(dialog-in) | |
| ``` | |
| Так несколько веток сходятся в один общий вопрос без дублирования нод. | |
| ### Зацикливание knowledge-вопросов | |
| ```text | |
| Question "Что узнать?"(turn) -> Knowledge Answer(turn) | |
| Knowledge Answer(dialog) -> Question "Еще вопросы?"(dialog-in) | |
| ``` | |
| Так пользователь может задавать вопросы по файлу, пока не ответит, что больше вопросов нет. | |
| ## LLM answer и LLM Test | |
| ### LLM answer | |
| Разово генерирует ответ пользователя на текущий вопрос. | |
| ### Auto LLM answer | |
| Автоматически отвечает на каждый новый вопрос тем же prompt-ом тестового пользователя. | |
| Prompt хранится в workflow JSON: | |
| ```json | |
| { | |
| "settings": { | |
| "llmRolePrompt": "..." | |
| } | |
| } | |
| ``` | |
| ### LLM Test | |
| Отдельный режим тестирования сценария: | |
| 1. LLM проходит сценарий как пользователь. | |
| 2. После вопросов/ответов ассистента evaluator проверяет адекватность. | |
| 3. Если evaluator видит проблему, в JSONL-лог первым событием пишется причина. | |
| 4. Полный trace LLM-запросов сохраняется в `test_logs/`. | |
| `LLM Test` можно остановить кнопкой `Stop LLM Test`. | |
| ## Логи | |
| ### UI logs | |
| Правая панель показывает служебные события, ошибки, проверки evaluator и пути к файлам логов. | |
| При `Auto LLM answer` и `LLM Test` обычные реплики не дублируются в правый служебный log, потому что они уже видны в transcript. | |
| ### Write logs | |
| Галочка `Write logs` пишет простой текстовый transcript: | |
| ```text | |
| ASSISTANT: ... | |
| USER: ... | |
| ``` | |
| Файлы создаются в: | |
| ```text | |
| transcript_logs/<workflow-name>/ | |
| ``` | |
| Эта папка не коммитится. | |
| ### Test logs | |
| `LLM Test` пишет подробные JSONL trace-файлы: | |
| ```text | |
| test_logs/<workflow-name>/ | |
| ``` | |
| Если evaluator считает вопрос или ответ плохим, первая строка файла будет `evaluation_failure_summary` с причиной. | |
| ## Скриншоты | |
| Скриншоты UI лучше хранить отдельно от runtime-логов, например: | |
| ```text | |
| scenarios/screenshots/ | |
| ``` | |
| Рекомендуемые скрины для README: | |
| - общий вид canvas с RosUpack workflow; | |
| - нижняя interactive panel во время прогона; | |
| - пример `Knowledge Answer` ноды с привязанным файлом; | |
| - пример `Semantic Branch` с альтернативами через `;`. | |
| ## Git hygiene | |
| В репозиторий должны попадать: | |
| - `src/` | |
| - `backend/main.py` | |
| - `backend/requirements.txt` | |
| - `public/` | |
| - `workflows/` | |
| - `scenarios/` | |
| - конфиги приложения | |
| В репозиторий не должны попадать: | |
| - `node_modules/` | |
| - `dist/` | |
| - `backend/.venv/` | |
| - `knowledge_contexts/` | |
| - `test_logs/` | |
| - `transcript_logs/` | |
| ## GitHub | |
| Repository: | |
| ```text | |
| https://github.com/markitzeroo/nodes-ui-flow | |
| ``` | |
| Repository is private. | |