Files
site-portfolio/src/pages/cases/ai-platform-primo-rpa.html
T
root 16dafcbf01 chore: удалена пустая секция section--surface после контактов
Убран инклюд {{> footer-spacer}} (пустая <section class="section section--surface"
aria-hidden> как прокладка перед футером) на главной и во всех 16 кейсах.
Пересобраны страницы (build:pages).
2026-09-08 18:15:04 +02:00

594 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru" data-theme="dark" data-radius="medium" data-font="merriweather">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta
name="description"
content="Кейс: интерфейс AI Server в Primo RPA — OCR на корпоративных документах, дообучение моделей, skills, UX/UI."
/>
<title>AI Server в Primo RPA — кейс</title>
{{> head-links}}
{{> head-plyr}}
<style>
.case-article {
max-width: 48rem;
margin: 0 auto;
}
.case-article h2 {
margin: 2rem 0 0.75rem;
font-size: clamp(1.15rem, 2vw, 1.35rem);
font-weight: 700;
color: var(--text);
}
.case-article h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
}
.case-article .section__prose {
margin-bottom: 0.75rem;
color: var(--text);
}
.case-article img,
.case-article video {
display: block;
max-width: 100%;
height: auto;
margin: 0.75rem 0 1rem;
}
.case-article ul,
.case-article ol {
margin: 0.5rem 0 1rem 1.25rem;
padding: 0;
}
.case-article li {
margin-bottom: 0.35rem;
}
.case-article a:not(.btn) {
color: var(--accent);
}
.case-block {
margin-top: 3rem;
padding-top: 2.5rem;
border-top: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
}
.case-block:first-of-type {
margin-top: 0;
padding-top: 0;
border-top: 0;
}
</style>
<script>
(function () {
try {
var t = JSON.parse(localStorage.getItem("siteThemeV1") || "{}");
var d = document.documentElement;
var m = t.mode;
if (m !== "light" && m !== "dark" && m !== "system") m = "system";
var eff =
m === "system"
? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
: m;
d.dataset.theme = eff;
var h = typeof t.h === "number" ? t.h : typeof t.hue === "number" ? t.hue : null;
var s = typeof t.s === "number" ? t.s : typeof t.sat === "number" ? t.sat : null;
var l = typeof t.l === "number" ? t.l : typeof t.light === "number" ? t.light : null;
if (h !== null) d.style.setProperty("--theme-h", String(h));
if (s !== null) d.style.setProperty("--theme-s", String(s));
if (l !== null) {
var L = Number(l);
if (Number.isFinite(L)) d.style.setProperty("--theme-l", String(Math.min(70, Math.max(20, L))));
}
var rad = t.radius;
if (rad === "soft" || rad === "medium" || rad === "strong") {
d.dataset.radius = rad;
} else {
d.dataset.radius = "medium";
}
var f = t.font;
if (f === "onest") f = "geologica";
if (f === "anonymous") f = "mono";
if (f === "merriweather" || f === "mono" || f === "geologica") {
d.dataset.font = f;
} else {
d.dataset.font = "merriweather";
}
var mb = t.meshBg;
if (mb === "off") {
d.dataset.meshBg = "off";
} else {
d.dataset.meshBg = "on";
}
} catch (e) {}
})();
</script>
</head>
<body data-current-case="ai-platform-primo-rpa">
{{> header-case}}
{{> fab-stack}}
<main id="case-main" class="section section--tight">
<div class="section__inner case-article">
<p class="hero__eyebrow">Product Design · AI</p>
<h1 class="case-page__h1">Разработка интерфейса для&nbsp;Primo&nbsp;RPA&nbsp;AI&nbsp;Server</h1>
<p class="case-page__sub">
Платформа интеллектуальной обработки документов<br />
и оркестрации ИИ-агентов
</p>
<div class="case-block" id="obzor">
<h2>Обзор</h2>
<p class="section__prose">
Продукт AI Server разворачивается на внутренних серверах клиентов. Он позволяет использовать нейросети во внутреннем контуре компании и настраивается через веб-интерфейс.
</p>
<p class="section__prose">
Меня пригласили на проект как UX/UI-дизайнера. Продукт был в активной стадии тестирования; по обратной связи от клиентов стало ясно, что настройка слишком сложна: с ней справляются только эксперты и команда внедрения Primo RPA. Сложная настройка снижала привлекательность продукта и тормозила масштабирование.
</p>
<p class="section__prose">
Передо мной стояла задача упростить настройку и снизить порог входа, разгрузить техподдержку и отдел внедрения — чтобы клиенты могли самостоятельно настраивать сервис под свои задачи.
</p>
<aside class="case-callout" data-callout>
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
<div class="case-callout__content">
<p>
Бизнес ставил цель — упростить настройку AI Server и сделать продукт доступнее для клиента. От меня ждали интерфейса, в котором настройку можно пройти без постоянной помощи поддержки и внедрения.
</p>
</div>
</aside>
<p class="section__prose">
Ниже — погружение в продукт, примеры выполненных задач и паттерны интерфейса.
</p>
</div>
<div class="case-block" id="pogruzhenie">
<h2>Погружение</h2>
<p class="section__prose">
Работу начал со знакомства с командой: кто за продукт, кто за внедрение, как всё устроено сейчас. Пообщался с экспертами по настройке, разделил ключевые и вспомогательные сценарии, собрал визуализацию поведения пользователя. Плотно работал с разработкой и искал, где интерфейс можно упростить и ускорить настройку.
</p>
<aside class="case-callout" data-callout>
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✨</span>
<div class="case-callout__content">
<p>
Мой опыт в ИИ и в похожих веб-платформах помог быстрее разобраться в домене и говорить с разработкой на одном языке.
</p>
</div>
</aside>
<p class="section__prose">
Продукт уже использовали клиенты, поэтому нельзя было остановить разработку и пересобрать интерфейс целиком. Пришлось решать, в каком порядке и какие части трогать в редизайне. Самые крупные изменения встраивал в текущий план разработки, без отрыва от релизов.
</p>
<p class="section__prose">
Прорабатывать изменения в интерфейсе нужно было с учётом используемого фреймворка. На тот момент это был
<a href="https://ant.design/components/overview" target="_blank" rel="noopener noreferrer">Ant Design</a> под React со стилизацией под
<a href="https://templates.iqonic.design/hope-ui/html/dist/" target="_blank" rel="noopener noreferrer">Hope UI</a>.
</p>
<p class="section__prose">
Новые компоненты приходилось придумывать только в крайних случаях, в приоритете было переиспользовать уже существующую библиотеку. По итоговым экранам это видно: интерфейс в основном собран из готовых блоков, а не с нуля.
</p>
</div>
<div class="case-block" id="zadachi">
<h2>Выполненные задачи</h2>
<p class="section__prose">
Фрагменты интерфейса, которые я переработал или собрал почти с нуля. Ниже — отдельные задачи из проекта, которые хотелось показать в портфолио, а не обзор всего продукта.
</p>
<h3>Главная навигация сервиса</h3>
<p class="section__prose">
В сервисе стояла привычная для админок схема: слева боковое меню, справа контент. На скриншоте видно, что такая структура страницы неэффективно использовала доступное рабочее пространство на экране. Если открыть проект, слева окажется навигация по разделам проекта — вперемешку с главной, и это путает пользователя. Эту ситуацию нужно было исправить.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/main.webp"
alt="Предыдущая главная навигация сервиса AI Server"
width="2520"
height="1680"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Предыдущая навигация</figcaption>
</figure>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/main-new.webp"
alt="Обновлённая главная навигация сервиса AI Server"
width="1920"
height="1080"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Обновлённая навигация</figcaption>
</figure>
<p class="section__prose">
Обновлённая навигация стала компактной и всё так же привычна большинству пользователей. Для контентной части пространства стало значительно больше. Как будет видно дальше, у проектов внутри появится отдельная навигация, которая не будет перекрывать главную. При этом улучшилась эстетическая составляющая дизайна сервиса.
</p>
<h3>Навигация внутри конкретного проекта</h3>
<p class="section__prose">
У пользователя остаётся доступ и к навигации внутри проекта, и к главной навигации сервиса. Разные типы проекта содержат разное количество пунктов, и такое решение позволяет удачно их разместить.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-project-nlp.webp"
alt="Навигация внутри NLP-проекта и главная навигация сервиса"
width="1920"
height="302"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>NLP-проект</figcaption>
</figure>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-project-ocr.webp"
alt="Навигация внутри OCR-проекта и главная навигация сервиса"
width="1920"
height="302"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>OCR-проект</figcaption>
</figure>
<p class="section__prose">
Отдельно отмечу идею с формой пунктов навигации. По виду она мягко подсказывает, что настройку удобнее проходить по шагам, но разделы по-прежнему работают как обычные табы: можно переключаться в любом порядке.
</p>
<figure class="case-media">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-secondary-detail_view.webp"
alt="Вторичная навигация проекта со стрелочной формой пунктов"
width="924"
height="101"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Форма пунктов навигации</figcaption>
</figure>
<h3>Редактор разметки датасета</h3>
<p class="section__prose">
На этом экране проводят больше всего времени. Разметка полей на сотнях изображений — монотонная работа, но от неё зависит, насколько качественными будут данные для обучения модели. Прежний редактор сильно выбивался из общего стиля сервиса: выглядел перегруженно и местами сбивал с толку, особенно в работе с полями.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor-old.webp"
alt="Редактор датасета — предыдущая версия для сравнения"
width="1200"
height="675"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Предыдущая версия редактора датасета</figcaption>
</figure>
<p class="section__prose">
Я разобрал редактор на микросценарии, выстроил их по приоритету и связке между собой. С командой обсудили, как сделать поведение пользователя плавнее и понятнее. В новой структуре страницы заложил место под новый функционал и те же паттерны, что в остальном сервисе. Дизайн редактора привёл к общей стилистике.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor.webp"
alt="Редактор датасета — текущая версия интерфейса"
width="1200"
height="675"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Обновлённая версия редактора датасета</figcaption>
</figure>
<p class="section__prose">
На схематическом наброске видно, что страница стала симметричной: почти всё пространство уходит на размечаемое изображение. Действия сгруппированы по панелям — нужную функцию проще найти.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-default_mode.webp"
alt="Вайрфрейм редактора датасета — режим по умолчанию"
width="1200"
height="675"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Каркас: режим по умолчанию</figcaption>
</figure>
<p class="section__prose">
Добавил режим «Во весь экран». Продвинутые пользователи обычно прячут лишние панели и работают с разметкой через горячие клавиши и нижнюю панель. Боковые панели можно свернуть, когда нужно больше места под изображение — на небольших мониторах это особенно имеет значение.
</p>
<figure class="case-media case-media-gallery case-media-gallery--wide" style="--case-gallery-cols: 2">
<div class="case-media-gallery__grid">
<div class="case-media-gallery__item">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-with-panels.webp"
alt="Полноэкранный режим с боковыми панелями"
loading="lazy"
decoding="async"
data-image-viewer
/>
</div>
<div class="case-media-gallery__item">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-zen.webp"
alt="Полноэкранный режим без отвлекающих панелей"
loading="lazy"
decoding="async"
data-image-viewer
/>
</div>
</div>
<figcaption>Вид редактора в режиме «Во весь экран»</figcaption>
</figure>
<figure class="case-media case-media-gallery case-media-gallery--wide" style="--case-gallery-cols: 2">
<div class="case-media-gallery__grid">
<div class="case-media-gallery__item">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-both_panels.webp"
alt="Вайрфрейм zen mode — обе панели"
loading="lazy"
decoding="async"
data-image-viewer
/>
</div>
<div class="case-media-gallery__item">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode.webp"
alt="Вайрфрейм zen mode"
loading="lazy"
decoding="async"
data-image-viewer
/>
</div>
<div class="case-media-gallery__item">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-left_panel.webp"
alt="Вайрфрейм zen mode — левая панель"
loading="lazy"
decoding="async"
data-image-viewer
/>
</div>
<div class="case-media-gallery__item">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-right_panel.webp"
alt="Вайрфрейм zen mode — правая панель"
loading="lazy"
decoding="async"
data-image-viewer
/>
</div>
</div>
<figcaption>Варианты рабочего вида в режиме «На весь экран»</figcaption>
</figure>
<p class="section__prose">
Нижняя панель позволяет переключаться между изображениями и выполнять быстрые действия.
</p>
<figure class="case-media case-media--content">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-main_toolbar.webp"
alt="Главная панель инструментов редактора датасета"
width="1200"
height="675"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Нижняя панель инструментов</figcaption>
</figure>
<h3>Карточки настройки обучения модели</h3>
<p class="section__prose">
После разметки датасета модель можно дообучить (fine-tuning). Мы с командой, как обычно, разобрали все действия пользователя для этой задачи. Сделали несколько вариантов компоновки этой страницы; самым удачным оказался вариант с лентой из карточек.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-overview.webp"
alt="Обзор карточек настройки обучения в проекте"
width="1920"
height="740"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Вид раздела обучения моделей</figcaption>
</figure>
<p class="section__prose">
В начале ленты у пользователя карточка с настройкой обучения: через неё видно результат разметки активного датасета, задают параметры и запускают fine-tuning.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-new.webp"
alt="Карточка настройки обучения"
width="1306"
height="1104"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Карточка настройки обучения</figcaption>
</figure>
<p class="section__prose">
В карточке отдельный блок с оценкой качества разметки датасета и блок с параметрами перед запуском обучения.
</p>
<aside class="case-callout" data-callout>
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">⭐</span>
<div class="case-callout__content">
<p>
Матрица оценки качества датасета получилась и наглядной, и компактной.
</p>
</div>
</aside>
<p class="section__prose">
Под каждый запущенный процесс ниже появится отдельная карточка. Можно завести несколько процессов с разными параметрами и потом сравнить, какая конфигурация сработала лучше.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-learning_process.webp"
alt="Карточка процесса обучения модели"
width="1306"
height="1066"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Карточка процесса обучения</figcaption>
</figure>
<p class="section__prose">
Внутри карточки информация и действия разнесены по логическим блокам. Мы рассматривали разные варианты компоновки и в итоге зафиксировали схему, которая оказалась удобнее остальных.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-learning_process_wireframe.webp"
alt="Вайрфрейм карточки процесса обучения"
width="1306"
height="1066"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Вайрфрейм карточки процесса обучения</figcaption>
</figure>
<p class="section__prose">
Карточки могут быть свёрнуты. Для удобства в шапку вынесены название и статус.
</p>
<figure class="case-media case-media--content">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-сollapsed.webp"
alt="Свёрнутая карточка настройки обучения"
width="1306"
height="102"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Свёрнутая карточка</figcaption>
</figure>
<p class="section__prose">
После проработки этих карточек появились паттерны, которые потом использовались в других разделах продукта. Так проще держать интерфейс в едином стиле.
</p>
<h3>Настройка параметров полей</h3>
<p class="section__prose">
На одной из страниц раздела проекта нужно было дать возможность настроить уникальные параметры полей для датасета. Редактору требовалась большая область под изображение (скан документа), могло быть десятки полей, у каждого — свои зависимые параметры и типы.
</p>
<p class="section__prose">
На видео — работа прототипа готового решения.
</p>
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
<div class="case-video-shell">
<video
controls
preload="metadata"
playsinline
poster="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webp"
data-case-video-player
style="display: block; width: 100%; height: auto; margin: 0"
>
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webm" type="video/webm" />
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.mp4" type="video/mp4" />
Ваш браузер не поддерживает видео.
</video>
</div>
<figcaption>Сопоставление полей в интерфейсе</figcaption>
</figure>
<p class="section__prose">
Интерфейс получился компактным и лаконичным. Механика не считывается с первого взгляда, но после короткого обучения пользователю в нём комфортно.
</p>
<p class="section__prose">
Редактор для меня оказался интересной и сложной задачей: было много черновиков и вариантов поведения. В финале остался вариант, который закрывал все требования, которые мы с командой сформулировали.
</p>
<h3>Модальные окна на отдельном экране</h3>
<p class="section__prose">
В сервисе часть задач нужно выполнять параллельно с остальной работой. Для таких сценариев сделали так: модальное окно открывается на отдельной странице.
</p>
<figure class="case-media case-media--wide">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.webp"
alt="Модальное окно импорта датасета на отдельном экране"
width="1440"
height="1024"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Импорт датасета в модальном окне</figcaption>
</figure>
<p class="section__prose">
На странице проекта отображается заглушка: процесс идёт, рядом кнопка перехода к нему.
</p>
<figure class="case-media case-media--content">
<img
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-in_project-import_dataset.webp"
alt="Импорт датасета внутри проекта"
width="1920"
height="740"
loading="lazy"
decoding="async"
data-image-viewer
/>
<figcaption>Импорт датасета внутри проекта</figcaption>
</figure>
<p class="section__prose">
Такие заглушки есть в нескольких разделах проекта — в зависимости от того, можно ли с ним работать, пока задача активна.
</p>
<aside class="case-callout" data-callout>
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
<div class="case-callout__content">
<p>
Пользователь может открыть окно с процессом в соседней вкладке и следить за прогрессом. В другой вкладке или окне продолжает работу с проектом в доступных разделах.
</p>
</div>
</aside>
<p class="section__prose">
Такой вариант оказался технически проще, чем точечно блокировать кнопки на отдельных страницах.
</p>
</div>
<div class="case-block" id="process">
<h2>Передача в разработку</h2>
<p class="section__prose">
Раз в неделю команда собиралась на обсуждение дизайна. Созвоны были длительными, но продуктивными. На неделю формировали список задач для дизайна, приоритеты и сроки подстраивали под планы релизов.
</p>
<p class="section__prose">
Я делал дизайн в Figma, в разработку передавал ссылки на готовые юзерфлоу. Отдельную дизайн-систему или UI-kit не заводили: в продукте уже был готовый фреймворк.
</p>
<p class="section__prose">
Время от времени созванивался с верстальщиком тет-а-тет, если нужно уточнить детали по макетам или объяснить поведение интерфейса. После вёрстки давал фидбэк на правки, чтобы результат не отличался от задуманного поведения и вида интерфейса.
</p>
</div>
<div class="case-block" id="smena-dizaynera">
<h2>Смена дизайнера</h2>
<p class="section__prose">
Проект вёл параллельно с другими, нагрузку приходилось распределять. В компанию наняли нового дизайнера — моя задача была ввести её в курс дела и курировать результат по задачам. После адаптации работа над проектом полностью перешла под её ответственность.
</p>
</div>
<div class="case-block" id="zaklyuchenie">
<h2>Итог</h2>
<p class="section__prose">
Интерфейс Primo RPA AI Server стал выглядеть консистентно. С ним могут работать пользователи, которые ещё не эксперты в области ИИ. Для будущих изменений в интерфейсе заложена возможность наращивать функционал без больших переделок.
</p>
</div>
</div>
</main>
{{> projects-related}}{{> projects-section}}
{{> contact-section}}
{{> footer}}
{{> cookie-notice}}
{{> nav-more-floating}}
<script>
document.addEventListener('DOMContentLoaded',function(){
var s=document.body.dataset.currentCase;
if(!s)return;
document.querySelectorAll('[data-related-slug="'+s+'"]').forEach(function(el){el.hidden=true;});
});
</script>
</body>
</html>