09 - Docker files

Continuação do artigo:
08 - Diagramas Mermaid e visão geral de serviços + contextos

Segue o pacote completo ❤️


docker-compose.yml consolidado

version: "3.9"

services:
  # ---------------------------------------------------------
  # 1) Job de treino – gera model/model.onnx
  # ---------------------------------------------------------
  trainer:
    container_name: trainer-product-category
    build:
      context: .
      dockerfile: Dockerfile.ml
    volumes:
      - ./model:/app/model
    command: ["python", "ml/train_product_category.py"]

  # ---------------------------------------------------------
  # 2) API de Embeddings interna (Go + OpenAI)
  # ---------------------------------------------------------
  embeddings-api:
    container_name: embeddings-api
    build:
      context: .
      dockerfile: Dockerfile.embeddings-api
    environment:
      # Observabilidade
      - OTEL_EXPORTER_OTLP_ENDPOINT=tempo:4317

      # OpenAI
      - OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - OPENAI_EMBEDDINGS_MODEL=${OPENAI_EMBEDDINGS_MODEL:-text-embedding-3-small}

      # Auth da própria API de embeddings (Bearer token)
      - EMBEDDINGS_API_TOKEN=${EMBEDDINGS_API_TOKEN:-changeme}
    ports:
      - "8080:8080"
    depends_on:
      - tempo

  # ---------------------------------------------------------
  # 3) Product Category API (Go + ONNX)
  # ---------------------------------------------------------
  product-category-api:
    container_name: product-category-api
    build:
      context: .
      dockerfile: Dockerfile.api-go
    volumes:
      - ./model:/app/model:ro
    environment:
      # ONNX
      - ONNXRUNTIME_LIB=/usr/local/lib/libonnxruntime.so
      - MODEL_PATH=/app/model/model.onnx

      # Observabilidade
      - OTEL_EXPORTER_OTLP_ENDPOINT=tempo:4317

      # Client de embeddings (chamando embeddings-api)
      - EMBEDDINGS_PROVIDER=http
      - EMBEDDINGS_BASE_URL=http://embeddings-api:8080
      - EMBEDDINGS_CUSTOM_PATH=/v1/embeddings/product
      # Reuso do mesmo token para chamar a embeddings-api
      - EMBEDDINGS_API_KEY=${EMBEDDINGS_API_TOKEN:-changeme}
    ports:
      - "8000:8000"
    depends_on:
      - embeddings-api
      - tempo

  # ---------------------------------------------------------
  # 4) Prometheus (métricas)
  # ---------------------------------------------------------
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
    ports:
      - "9090:9090"
    depends_on:
      - product-category-api
      - embeddings-api

  # ---------------------------------------------------------
  # 5) Loki (logs)
  # ---------------------------------------------------------
  loki:
    image: grafana/loki:3.0.0
    container_name: loki
    command: -config.file=/etc/loki/config.yml
    volumes:
      - ./loki/config.yml:/etc/loki/config.yml
      - ./loki/data:/loki
    ports:
      - "3100:3100"

  # ---------------------------------------------------------
  # 6) Promtail (coletor de logs -> Loki)
  # ---------------------------------------------------------
  promtail:
    image: grafana/promtail:3.0.0
    container_name: promtail
    command: -config.file=/etc/promtail/config.yml
    volumes:
      - ./promtail/config.yml:/etc/promtail/config.yml
      # Ajustar paths conforme seu ambiente Docker/WSL
      - /var/log:/var/log
      - /var/lib/docker/containers:/var/lib/docker/containers
    depends_on:
      - loki

  # ---------------------------------------------------------
  # 7) Tempo (traces OTEL)
  # ---------------------------------------------------------
  tempo:
    image: grafana/tempo:2.6.0
    container_name: tempo
    command: [ "-config.file=/etc/tempo/tempo.yml" ]
    volumes:
      - ./tempo/tempo.yml:/etc/tempo/tempo.yml
      - ./tempo/data:/tmp/tempo
    ports:
      - "3200:3200"  # HTTP
      - "4317:4317"  # OTLP gRPC

  # ---------------------------------------------------------
  # 8) Grafana (dashboard)
  # ---------------------------------------------------------
  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASS:-admin}
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
      - loki
      - tempo
    volumes:
      - ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
      - ./grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards
      - ./grafana/dashboards:/var/lib/grafana/dashboards

README.md – padrão “Farsoft”

# Farsoft – ML Stack de Categorização de Produtos

Projeto de referência para:

- Treinar um modelo de **categorização de produto** (ex.: AUTOPEÇAS, INFORMÁTICA, MATERIAL_CONSTRUÇÃO)
- Exportar para **ONNX**
- Servir via **Product Category API** (Go + chi + ONNX Runtime)
- Usar uma **Embeddings API interna** (Go) que pode:
  - chamar **OpenAI Embeddings**, ou
  - chamar outro provider no futuro
- Integrar tudo com **Prometheus + Grafana + Loki + Tempo** (observabilidade completa)

Arquitetura pensada para encaixar no ecossistema Farsoft (contextos `erp`, `ml`, `platform`).

---

## Visão Geral do Fluxo

Fluxo principal:

```text
Treino (Python) -> model.onnx -> Product Category API (Go) -> ERP

Product Category API -> Embeddings API -> OpenAI (ou outro provider)
                    -> ONNX Runtime -> Categoria + probabilidades

APIs -> Prometheus/Loki/Tempo -> Grafana (dashboards)

1. Treino

2. Embeddings API (embeddings-api)

3. Product Category API (product-category-api)


Observabilidade

Stack:

Endpoints de observabilidade


Estrutura de Diretórios (resumida)

.
├── docker-compose.yml
├── Makefile
├── Taskfile.yml
├── model/                      # ONNX gerado pelo trainer
├── ml/
│   └── train_product_category.py
├── product-category-api/
│   └── internal/
│       ├── erp/productcategory/
│       ├── ml/onnx/
│       ├── ml/embeddingsclient/
│       └── platform/
│           ├── http/
│           └── observability/
├── embeddings-api/
│   └── internal/
│       ├── erp/product/
│       ├── ml/embeddings/
│       └── platform/
│           ├── http/
│           └── observability/
├── prometheus/
│   └── prometheus.yml
├── loki/
│   └── config.yml
├── tempo/
│   └── tempo.yml
├── promtail/
│   └── config.yml
└── grafana/
    ├── provisioning/
    │   ├── datasources/
    │   │   └── datasources.yml
    │   └── dashboards/
    │       └── dashboards.yml
    └── dashboards/
        └── product-api.json

Fluxo de Uso

1. Build das imagens

make build
# ou
task build

2. Treinar o modelo (gera model/model.onnx)

make train
# ou
task train

3. Subir APIs + Observabilidade

make up
# ou
task up

Serviços principais:

4. Testar classificação por descrição

curl -X POST http://localhost:8000/predict-description \
  -H "Content-Type: application/json" \
  -d '{"descricao": "Pastilha de freio dianteira Corolla 2018"}'

5. Observar métricas e logs


Variáveis de Ambiente Importantes

No seu .env ou ambiente:

# OpenAI
OPENAI_API_KEY=sk-...
OPENAI_BASE_URL=https://api.openai.com
OPENAI_EMBEDDINGS_MODEL=text-embedding-3-small

# Auth da embeddings-api
EMBEDDINGS_API_TOKEN=algum-token-forte

# Grafana
GRAFANA_USER=admin
GRAFANA_PASS=admin

Próximos Passos Naturais

Farsoft – ML encaixado no ERP, observável, versionável e plugável. 🙂