Демьяненко Ирина - backend Вешкина Полина - frontend Черкасов Борис - backend/ML Гавриш Вероника - backend/ML
Для подробного просмотра кейса смотреть в pdf-file: ![тык]
На текущий момент у нас готов полностью рабочий прототип, включающий:
- веб-интерфейс для загрузки данных, просмотра текстов, аналитики и поиска;
- бэкенд с REST API и встроенной логикой обработки данных;
- инфраструктуру для подключения ML-модели — она уже интегрирована и протестирована на заглушке.
Наша собственная модель сейчас находится в финальном этапе обучения, и мы ждём один итоговый файл весов.
Вся остальная структура модели — конфигурация, токенизатор, код обучения — уже помещены в репозиторий.
Интеграция на стороне бэкенда полностью готова: сервис загружает модель один раз при старте и работает с ней эффективно.
То есть нам осталось всего лишь добавить итоговый файл весов, и система станет полностью рабочей уже на нашей модели.
Также у нас уже подготовлена инфраструктура для развертывания: весь проект упакован в Docker-контейнеры и запускается через Docker Compose. После получения финального файла модели мы сможем развернуть проект на сервере.
Сейчас мы можем развернуть проект локально и продемонстрировать работу интерфейса, API и всех функций системы. А по вопросам, связанным с моделью, сможет подробно ответить наш ML-специалист. А сейчас предлагаю оценить работу прототипа
(место для ссылки работы прототипа)
Full-stack web приложение для определения тональности текстов, использует FastAPI и React.
- Загружать данные
- Модель автоматически определит тональность + confidence (уверенность в правильности)
- Пользователь может просмотреть, отфильтровать и исправлять ошибки
- Получать быструю аналитику и метрики качества.
Наш API разделён на три логических блока: загрузка датасетов, управление текстами и аналитика. При загрузке данных мы автоматически запускаем ML-модель, которая для каждого текста определяет его тональность и уверенность. Пользователь может корректировать результат, а раздел аналитики показывает статистику, распределение тональностей и качество модели на реальных данных.
Сервис доступен по ссылке: Документация API доступна по ссылке: http://localhost:8000/docs#//
Сервис доступен по ссылке: http://localhost:5173/
Почему мы выбрали FastAPI FastAPI - оптимальный выбор, когда нужно быстро построить работающий ML-сервис с хорошей скоростью и удобным API для фронтенда.
Быстро FastAPI — один из самых быстрых Python-фреймворков. Он работает асинхронно, поэтому отлично справляется с задачами, где нужно быстро обрабатывать тексты и получать предсказания от ML-модели.
Удобно для ML FastAPI идеально подходит для интеграции с моделями на PyTorch / Transformers:
- модель загружается один раз при старте,
- предсказания работают мгновенно,
- JSON-ответы формируются автоматически.
Фронтенд на React общается с FastAPI через обычный REST-API. Интерфейс легко интегрируется без сложной конфигурации.
- Быстро разворачивается
- Есть автодокументация /docs
- Отлично работает с ML-моделями
- Минимальные требования к инфраструктуре
Требования:
- Docker
- Docker Compose
Клонировать репозиторий:
git clone https://hub.mos.ru/boris.cherkasov/hack_change-2025.git
cd hack_change-2025Запуск:
docker compose up -d --buildПриложение доступно по адресам:
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/docs
.
├── backend/
│ ├── app/
│ │ ├── models/
│ │ │ └── schemas.py # Pydantic models
│ │ ├── routers/
│ │ │ ├── datasets.py # Upload endpoints
│ │ │ ├── texts.py # Text management
│ │ │ └── analytics.py # Statistics & evaluation
│ │ ├── services/
│ │ │ ├── sentiment_model.py # ML model
│ │ │ ├── database.py # Supabase client
│ │ │ └── evaluation.py # Metrics calculation
│ │ └── main.py # FastAPI app
│ ├── ml_models/ # Trained models
│ ├── requirements.txt
│ ├── Dockerfile
│ └── .env
├── src/
│ ├── components/
│ │ ├── Dashboard.tsx # Main dashboard
│ │ ├── UploadPage.tsx # File uploads
│ │ ├── TextsTable.tsx # Data table
│ │ ├── AnalyticsPage.tsx # Evaluation
│ │ └── SearchPage.tsx # Search interface
│ ├── lib/
│ │ ├── api.ts # API client
│ │ └── supabase.ts # Supabase client
│ └── App.tsx # Main app
├── docker-compose.yml
└── README.md
POST /api/upload-dataset- Принимает CSV с колонками source и text, возвращает тональность и уверенность модели Пример ответа:
{
"message": "Dataset uploaded successfully",
"dataset_id": "1ae99c4d-ac3e-4887-af5b-5b19c15f1b87",
"records_processed": 20
}
POST /api/upload-validation- Принимает CSV с истинными метками тональности. • Используется для оценки качества модели (F1, precision, recall).
{
"message": "Validation dataset uploaded successfully",
"records_processed": 10
}
GET /api/texts- Возвращает список текстов, поддерживает фильтры: источник, тональность, уверенность Пример ответа:
{
"items": [
{
"source": "twitter",
"text": "Отличный сервис, всё очень понравилось!",
"predicted_sentiment": "positive",
"corrected_sentiment": null,
"confidence": 0.91,
"id": "44123b51-8095-42a5-b55c-34f6f3d4d2e8",
"dataset_id": "f540b261-7e6b-4c34-8de8-cb7a62f5b72d",
"created_at": "2025-11-29T19:24:36.879Z",
"updated_at": "2025-11-29T19:24:36.879Z"
},
...
{
"source": "instagram",
"text": "It's okay, nothing special but does the job.",
"predicted_sentiment": "neutral",
"corrected_sentiment": null,
"confidence": 0.6297911112696108,
"id": "49163842-9409-4b74-ade3-a7a9fba94773",
"dataset_id": "de617305-977f-44cf-a613-af6050b65374",
"created_at": "2025-11-29T16:39:11.892747Z",
"updated_at": "2025-11-29T16:39:11.892747Z"
}
],
"total": 20,
"page": 1,
"page_size": 20,
"total_pages": 1
}
PUT /api/texts/{id}- Позволяет вручную исправить тональность, сохраняет историю изменений
Если id: f33d27de-c1dc-4be5-8eb7-c7a46d04522b
Ответ:
{
"message": "Text updated successfully",
"item": {
"dataset_id": "de617305-977f-44cf-a613-af6050b65374",
"source": "facebook",
"text": "Terrible customer service. Very disappointed with the quality.",
"predicted_sentiment": "negative",
"confidence": 0.4807974055824927,
"id": "f33d27de-c1dc-4be5-8eb7-c7a46d04522b",
"corrected_sentiment": "string",
"created_at": "2025-11-29T16:39:11.892740+00:00",
"updated_at": "2025-11-29T19:45:25.236856+00:00"
}
}
POST /api/search- Расширенный поиск по текстам Пример запроса:
{
"query": "разочар",
"sources": ["facebook", "twitter"],
"sentiment": "negative",
"min_confidence": 0.3,
"page": 1,
"page_size": 20
}
Ответ содержит такую же структуру, как /api/texts.
GET /api/statistics- Общая статистика по текстам Пример ответа:
{
"total_texts": 60,
"sentiment_distribution": {
"positive": 4,
"string": 1,
"neutral": 7,
"negative": 48
},
"avg_confidence": 0.3698237007608563,
"corrected_count": 1,
"by_source": {
"twitter": 18,
"facebook": 15,
"instagram": 15,
"reddit": 12
}
}
POST /api/evaluate- Считает метрики модели Пример ответа:
{
"macro_f1": 0.3222027972027972,
"precision": {
"nan": 0,
"negative": 0.058823529411764705,
"neutral": 0.375,
"positive": 0.8
},
"recall": {
"nan": 0,
"negative": 0.3333333333333333,
"neutral": 0.6,
"positive": 0.6666666666666666
},
"f1_score": {
"nan": 0,
"negative": 0.1,
"neutral": 0.4615384615384615,
"positive": 0.7272727272727272
},
"confusion_matrix": [
[
0,
12,
4,
0
],
[
0,
1,
1,
1
],
[
0,
2,
3,
0
],
[
0,
2,
0,
4
]
],
"labels": [
"nan",
"negative",
"neutral",
"positive"
]
}
GET /api/export- Экспортирует размеченные тексты в CSV с колонками: • text • source • predicted_sentiment • corrected_sentiment • confidence • created_at Позволяет выгрузить результаты для отчёта или демонстрации.
Пример ответа:
Пример ответа:
id,source,text,predicted_sentiment,corrected_sentiment,confidence,created_at
5c497b16-5a1f-4336-952c-52de7fbd9663,twitter,This product is absolutely amazing! Best purchase ever!,positive,,0.5090228910157258,2025-11-29T16:39:11.892712+00:00
f33d27de-c1dc-4be5-8eb7-c7a46d04522b,facebook,Terrible customer service. Very disappointed with the quality.,negative,string,0.4807974055824927,2025-11-29T16:39:11.892740+00:00
49163842-9409-4b74-ade3-a7a9fba94773,instagram,"It's okay, nothing special but does the job.",neutral,,0.6297911112696108,2025-11-29T16:39:11.892747+00:00
45542663-7246-4fad-889d-7b65c60ece39,twitter,Love it! Exceeded all my expectations!,neutral,,0.3961913069961781,2025-11-29T16:39:11.892756+00:00
9c096627-4026-454e-b2d8-f2450dc63a90,reddit,Worst experience ever. Would not recommend to anyone.,negative,,0.45164074475189375,2025-11-29T16:39:11.892761+00:00
Dataset Upload:
source,text
Моя москва,"После обновления стало быстрее работать, особенно раздел «Дом»."
Госуслуги Москвы,"Записалась к врачу без звонков и очередей — супер."
Наш город,"Подал заявку на неубранный двор — через день всё сделали."
Активный гражданин,"Голосования интересные, нравится ощущение участия в городских решениях."Validation Upload:
text,sentiment
Это лучшее, что я когда-либо покупала!,positive
Абсолютно ужасный продукт. Полная трата денег.,negative
Работает как и ожидалось. Ничего больше.,neutralФронтенд данного проекта реализован как SPA на React с использованием TypeScript. React — это популярная библиотека JavaScript для построения пользовательских интерфейсов, а TypeScript добавляет статическую типизацию и обнаружение ошибок на этапе разработки. Компоненты написаны как функциональные и используют хуки (useState, useEffect) для управления состоянием и побочными эффектами. Например, данные загружаются из API в хуке useEffect, а useState хранит результат запроса. Стилизация во всём приложении выполнена с помощью Tailwind CSS — утилитарного CSS-фреймворка, который генерирует стили на основе классов, используемых в JSX. Tailwind предоставляет множество готовых классов для отступов, цветов, сеток и т.д., делая разработку интерфейса быстрой и гибкой. Иконки (например, BarChart3, Search, Upload, FileText, CheckCircle и т.д.) берутся из библиотеки Lucide React, которая предоставляет SVG-иконки в виде React-компонентов. Это позволяет легко вставлять графические элементы (стрелки, значки) прямо в JSX-код.
Главный компонент App.tsx содержит верхнюю навигацию и отвечает за переключение страниц. При клике по кнопкам меню (Dashboard, Upload, Texts, Analytics, Search) меняется локальное состояние currentPage и отображается соответствующая компонента без полного перезагрузки (SPA-подход). Таким образом реализован «маршрутизатор» без использования библиотек для роутинга — текущая страница выводится через конструкцию switch.
Основные разделы приложения:
- Панель «Dashboard» (Dashboard.tsx): показывает суммарную статистику по текстам. Отображаются карточки с показателями: Total Texts (общее число записей), Avg Confidence (средний процент достоверности), Corrected (число исправленных вручную записей) и Sources (количество источников). Данные берутся асинхронно из метода api.getStatistics(). Также представлено распределение настроений (positive/negative/neutral) в виде полосок, где длина заливки пропорциональна проценту текстов данного настроения. Топ-5 источников выводятся списком с указанием количества записей. Данная страница иллюстрирует типичную панель администратора: статистика выводится динамически, а интерфейс выполнен в виде карточек и списков с помощью Tailwind.
- Страница «Upload» (UploadPage.tsx): содержит две секции для загрузки файлов CSV. В разделе Dataset Upload пользователь выбирает файл с колонками source,text и нажимает «Upload», после чего вызывается api.uploadDataset. В разделе Validation Dataset Upload аналогично загружается CSV с колонками text,sentiment через api.uploadValidation. Результаты операций отображаются сообщением об успехе или ошибке в виде цветных баннеров (зелёный для успеха, красный для ошибки). Для создания зон загрузки и кнопок также использованы Tailwind-классы (рамка border-dashed, центрирование, иконки Upload/FileText). Логика загрузки построена на асинхронных функциях и await, а при выборе файла появляется кнопка «Upload» для отправки запроса.
- Страница «Texts» (TextsTable.tsx): реализует отображение таблицы текстов с возможностью фильтрации и редактирования. В верхней части — фильтры по источнику (текстовое поле), по настроению (select) и по минимальной уверенности (min_confidence). При изменении фильтров или номера страницы (page) в useEffect делается запрос api.getTexts(params), где параметры включают выбранные фильтры и пагинацию. Таблица содержит столбцы: Source, Text, Sentiment, Confidence, Actions. Для каждого текста можно нажать кнопку редактирования (иконка Edit2), после чего значение «Sentiment» заменяется на выпадающий список со значениями positive/negative/neutral, и появляются кнопки сохранить/отменить (иконки Save, X). При сохранении вызывается api.updateText(id, newSentiment), затем обновляются данные таблицы. Внизу таблицы реализована пагинация кнопками «<»/«>», где текущая страница хранится в стейте. Такой подход (разбиение на страницы) облегчает навигацию по большому объёму данных: как отмечается в статье, _«пагинация, также называемая постраничной навигацией, разделяет информацию на странице и улучшает удобство использования». Параметры пагинации (page_size = 20) передаются в запрос.
- Страница «Analytics» (AnalyticsPage.tsx): предназначена для оценки качества модели классификации настроений. При нажатии на кнопку «Run Evaluation» запускается api.evaluateModel(), результатом которого является набор метрик качества (EvaluationMetrics). После этого отображаются: Macro F1 Score в виде большой карточки (с числом в процентах) и таблицы по классам для precision, recall и F1 Score (каждое — отдельный <MetricTable>). Также строится матрица ошибок (confusion matrix) с подсветкой по главной диагонали. Есть кнопка «Export Data», которая генерирует CSV-файл с данными (через api.exportData('csv') и создание ссылки для скачивания). Таким образом пользователь может получить и проанализировать метрики работы модели.
- Страница «Search» (SearchPage.tsx): реализует поиск по загруженным текстам. Содержит поле ввода запроса, кнопки фильтров (по настроению и минимальной уверенности) и кнопку «Search». При поиске формируются параметры и вызывается api.searchTexts(params), возвращающий постраничный результат. Найденные тексты выводятся карточками: у каждого указаны источник, текст, текущее настроение (corrected или predicted) с цветной меткой (зелёная, красная или серая, в зависимости от sentiment) и процент уверенности. Если результатов нет, показывается сообщение «No results found». Такой поиск позволяет быстро найти тексты по ключевым словам и фильтровать их по дополнительным критериям.
- Дашборд с ключевыми метриками. Общее число записей, средняя уверенность предсказаний, число исправленных меток, распределение настроений и наиболее «популярные» источники.
- Загрузка данных. Поддержка импорта CSV-файлов: отдельный загрузчик для обучающей выборки (с source,text) и для тестовой (с text,sentiment). Успешная загрузка отображается уведомлением.
- Просмотр и редактирование текстов. Таблица всех загруженных текстов с пагинацией, фильтрами (по источнику, настроению, порогу уверенности) и функцией ручной коррекции настроений.
- Оценка модели. Запуск вычисления метрик на тестовой выборке с выводом F1-score и прочих показателей по классам, а также визуализация матрицы ошибок. Возможность экспортировать результаты в CSV.
- Поиск по текстам. Интерфейс для поиска текстов по ключевым словам с фильтрацией по настроению и уверенному уровню, результаты отображаются как список с метками и датой.
- React + TypeScript. Проект создан с помощью Create React App с поддержкой TypeScript. Такая связка упрощает поддержку кода: TypeScript вводит строгую типизацию, что «значительно снижает вероятность ошибок во время выполнения»
- Tailwind CSS. Весь интерфейс стилизован утилитарными классами Tailwind. Это позволяет быстро создавать адаптивные и согласованные макеты без написания кастомного CSS
- Lucide Icons. Иконки используются из пакета lucide-react – это библиотека SVG-иконок, которые экспортируются как React-компоненты.Благодаря этому иконки масштабируемы и легко настраиваются через props (цвет, размер и т.д.) без потери качества.
- React Hooks. Для асинхронного получения данных из бэкенда используются хуки useEffect (для вызова API при загрузке компонента или изменении параметров) и useState (для хранения полученной информации)
Фронтенд взаимодействует с серверной частью через модуль api (в папке lib/api), который содержит функции для всех необходимых запросов: getStatistics, getTexts, searchTexts, uploadDataset, uploadValidation, evaluateModel, updateText, exportData и т.д. Все эти функции выполняются асинхронно и возвращают данные в формате JSON. Интерфейс обрабатывает ответы – отображает данные пользователю или показывает сообщения об ошибках (например, если запрос не удался).
Данный фронтенд обеспечивает удобный интерфейс для управления и анализа текстов настроений. Он сочетает в себе современные веб-технологии (React и TypeScript) и инструментальные библиотеки (Tailwind для стилизации, Lucide для иконок) для быстрого создания адаптивного и интерактивного приложения. Детали реализации компонентов, хуков и стилизации подробно описаны в коде; их поведение соответствует принятым подходам разработки React-приложений
The system uses a Naive Bayes classifier with TF-IDF vectorization:
- Features: TF-IDF with bi-grams
- Classes: positive, negative, neutral
- Output: Predicted sentiment + confidence score
- Training: Automatically initialized with default samples
- Macro F1 Score: Average F1 across all classes
- Precision/Recall/F1: Per-class metrics
- Confusion Matrix: Prediction accuracy breakdown
- Confidence: Model certainty (0-1)
Backend:
- FastAPI
- Scikit-learn
- Pandas
- Supabase Python Client
Frontend:
- React 18
- TypeScript
- Tailwind CSS
- Lucide Icons
- Vite
Infrastructure:
- Docker
- PostgreSQL (на стадии реализации)
- Row Level Security (RLS)