Sistema de recomendação de filmes com machine learning treinado diretamente no browser, sem infraestrutura de ML na nuvem.
O sistema aprende as preferências de cada usuário com base no histórico de filmes assistidos e recomenda novos títulos personalizados. O modelo é treinado localmente no browser usando TensorFlow.js em um Web Worker. Os vetores treinados são persistidos no PostgreSQL com pgvector, eliminando a necessidade de retreinamento a cada acesso.
- Cada filme é codificado em um vetor numérico com base em: gênero (one-hot, peso 40%), classificação etária (one-hot, peso 30%), rating IMDb (normalizado, peso 20%) e faixa etária do público (peso 10%)
- Cada usuário é representado pela média dos vetores dos filmes que assistiu
- A rede neural recebe pares
(usuário, filme)e aprende a prever se o usuário assistiria aquele filme - Para usuários sem histórico, o sistema usa similaridade por cosseno como fallback
- Os vetores treinados são salvos no banco com pgvector para reuso sem retreinamento
| Camada | Tecnologia |
|---|---|
| Frontend | JavaScript Vanilla, Web Workers |
| Machine Learning | TensorFlow.js 4.22 |
| Backend | Fastify 5, Node.js (ESM) |
| Banco de Dados | PostgreSQL 14 + pgvector |
| Containerização | Docker Compose |
| Arquitetura | Clean Architecture (backend) |
├── frontend/
│ ├── src/
│ │ ├── workers/
│ │ │ └── modelTrainingWorker.js # Treinamento ML em Web Worker
│ │ ├── service/MovieService.js # Consumo da API
│ │ ├── controller/ # Lógica de UI
│ │ └── events/constants.js # Eventos entre Worker e UI
│ └── data/
│ ├── movies.json # 9.957 filmes (dataset base)
│ └── users.json # Perfis de usuários com histórico
│
└── backend/
├── server.js # Entrada Fastify
├── src/
│ ├── domain/ # Entidades e interfaces
│ ├── application/useCases/ # InsertMovies, GetMovies, SaveVectors, GetVectors
│ ├── infra/
│ │ ├── database/
│ │ │ ├── migrate.js # Runner de migrations
│ │ │ └── migrations/
│ │ │ ├── 001_create_movies_table.sql
│ │ │ └── 002_create_vector_tables.sql # pgvector
│ │ └── repositories/
│ │ ├── MovieRepository.js
│ │ └── VectorRepository.js
│ └── interfaces/
│ ├── controller/
│ └── routes/
- Node.js 18+
- Docker e Docker Compose
- Yarn
cd backend
docker compose up -d# Na raiz do projeto
yarn installcd backend
node src/infra/database/migrate.js# Na raiz
yarn dev:backend
# ou
cd backend && node --watch server.js# Em outro terminal, na raiz
yarn dev:frontendFaça uma requisição POST para importar os 9.957 filmes:
curl -X POST http://localhost:3001/movies/import| Método | Rota | Descrição |
|---|---|---|
GET |
/health |
Status do servidor |
POST |
/movies/import |
Importa filmes do JSON para o banco |
GET |
/movies?limit=50&offset=0 |
Lista filmes paginada |
GET |
/movies/:id |
Busca filme por ID |
POST |
/vectors |
Salva vetores treinados no banco |
GET |
/vectors |
Retorna vetores da última sessão de treino |
Crie um arquivo .env dentro de backend/:
DB_HOST=localhost
DB_PORT=5432
DB_NAME=my_database
DB_USER=root
DB_PASSWORD=secret
PORT=30011. Abrir o frontend (localhost:3000)
2. Selecionar um usuário no select
3. Clicar em "Treinar Modelo"
→ Web Worker carrega 1.000 filmes do banco
→ Treina rede neural com class weights
→ Salva vetores no PostgreSQL via pgvector
4. Trocar de usuário → recomendações personalizadas imediatas
5. Ao recarregar a página → vetores são recuperados do banco (sem retreinamento)
- 9.957 filmes (títulos, gênero, rating IMDb, classificação etária, descrição)
- 5 perfis de usuários com 50 filmes assistidos cada
- Fonte: dataset público de filmes IMDb disponível no Kaggle
MIT