# Guia de Webhooks: Processar novos arquivos em um bucket com Jobs

[Storage Buckets](./storage-buckets) são um bom lugar para arquivos que chegam ao longo do tempo: exportações de outras ferramentas, logs, gravações, varreduras. Você frequentemente terá um fluxo de trabalho que precisa ser realizado nesses arquivos antes que eles sejam úteis, como convertê-los, limpá-los ou transcrevê-los.

Um webhook no bucket e um [Job](./jobs) podem executar esse trabalho automaticamente, sem um servidor. Quando os arquivos mudam, o webhook inicia o Job. O Job recebe a lista de arquivos alterados, processa-os e para. Você paga apenas enquanto ele está em execução.

Este guia explica o padrão e, em seguida, o configura com um exemplo: converter arquivos CSV e JSON enviados em Parquet otimizado.

## Como funciona

```text
file uploaded ──▶ webhook ──▶ Job runs with the event ──▶ result written to a second bucket
```

Um webhook pode [disparar um Job](./jobs-webhooks) em vez de chamar uma URL. Você cria o Job uma vez e cada evento de webhook o executa novamente com o evento em seu ambiente. Para um bucket, `WEBHOOK_PAYLOAD` lista os arquivos que foram alterados:

```json
{
  "event": { "action": "update", "scope": "repo.content" },
  "repo": { "type": "bucket", "name": "your-username/my-raw-files", ... },
  "updatedFiles": [
    { "path": "data.csv", "action": "add", "xetHash": "433b53b8...", "size": 10983 }
  ]
}
```

Portanto, o Job processa apenas os novos arquivos e pode decidir como lidar com cada um antes de baixar qualquer coisa.

Cada execução reutiliza a imagem, o comando, as variáveis de ambiente, o sabor de hardware e o tempo limite do Job. Ele não recebe os volumes do Job nem seus segredos. É por isso que as etapas abaixo executam o script a partir de uma URL e colocam o token no webhook.

O Job grava seus resultados em um **segundo bucket**. Se ele gravasse no bucket que ele monitora, sua própria saída dispararia o webhook novamente.

## Exemplo: transformar uploads em Parquet otimizado

Exportações em CSV e JSON são lentas para consultas e difíceis de compartilhar. [Parquet otimizado](./datasets-libraries#optimized-parquet-files) é mais rápido para filtrar e transmitir, e faz upload e download mais rápido graças à deduplicação do Xet. Neste exemplo, cada arquivo CSV, JSON ou Parquet enviado para um bucket aparece como Parquet otimizado em outro. O Job executa [`optimize-parquet.py`](https://huggingface.co/datasets/uv-scripts/data-processing/blob/main/optimize-parquet.py), um script pronto de [uv-scripts](https://huggingface.co/uv-scripts).

Você precisa de uma conta do Hugging Face com [créditos pré-pagos](https://huggingface.co/settings/billing) e o [`hf` CLI](https://huggingface.co/docs/huggingface_hub/en/guides/cli#getting-started).

### Crie dois buckets

Um bucket recebe seus uploads e o outro recebe os arquivos Parquet:

```bash
hf buckets create my-raw-files --private
hf buckets create my-parquet --private
```

### Criar o Job

Crie o Job que o webhook executará:

```bash
hf jobs run --flavor cpu-upgrade --timeout 2h \
    -e OUTPUT_BUCKET=your-username/my-parquet \
    ghcr.io/astral-sh/uv:python3.12-bookworm \
    uv run https://huggingface.co/datasets/uv-scripts/data-processing/raw/main/optimize-parquet.py
```

O script é executado a partir da sua URL, com `hf jobs run`. `hf jobs uv run` é a forma usual de executar um script UV, mas ele faz o upload do script para um volume, o que uma execução via webhook não teria. `cpu-upgrade` é suficiente para esse trabalho, e o timeout de duas horas deixa espaço para arquivos grandes.

O script também pode estar em um bucket ou repositório privado. Não use o bucket monitorado: o upload do script iniciaria um Job. Adicione `--secrets HF_TOKEN` ao comando, com um token que possa ler o script. Se a execução falhar com um `SyntaxError`, o token não consegue lê-lo. O token do webhook precisa do mesmo acesso, porque as execuções de webhook não recebem esse segredo.

`hf jobs run` inicia o Job imediatamente. Esta primeira execução não possui evento de webhook, e `optimize-parquet.py` não faz nada sem um, então o Job para imediatamente. Copie o ID do Job que ele imprime.

### Crie o webhook

Observe o primeiro bucket e execute seu Job quando ele for alterado:

```bash
hf webhooks create --job-id <job ID> --watch bucket:your-username/my-raw-files \
    --domain repo --secrets HF_TOKEN
```

`--domain repo` restringe o webhook a alterações em arquivos e configurações. Os buckets enviam apenas essas alterações, então isso é explícito em vez de necessário, mas mantém o comando correto caso você monitore um modelo ou dataset no futuro.

`--secrets HF_TOKEN` armazena um token no webhook, criptografado. Todo Job iniciado pelo webhook o recebe como um secret e o utiliza para ler e gravar nos buckets. O valor vem de `HF_TOKEN` no seu ambiente, ou do token com o qual você fez login. Um [token de granularidade fina](./security-tokens) com apenas as permissões necessárias para o Job é a opção mais segura.

> [!TIP]
> Para usar um token criado apenas para este pipeline, passe o valor explicitamente com `--secrets HF_TOKEN=hf_…`, ou mantenha-o fora do histórico do seu shell enviando-o por pipe: `printf 'HF_TOKEN=hf_…\n' | hf webhooks create … --secrets-file -`.

O comando exibe o ID do webhook. Para interromper o pipeline posteriormente, exclua o webhook com `hf webhooks delete <webhook ID>`.

### Enviar um arquivo

```bash
hf buckets cp data.csv hf://buckets/your-username/my-raw-files/data.csv
```

Aproximadamente um minuto depois, um Job aparece na sua [página de Jobs](https://huggingface.co/settings/jobs). Se nenhum aparecer, abra a aba Activity do webhook em suas [configurações de webhook](https://huggingface.co/settings/webhooks) para ver a entrega e leia a saída de um Job com `hf jobs logs <job ID>`. Quando o Job terminar, o arquivo Parquet estará no segundo bucket:

```bash
hf buckets ls your-username/my-parquet -R
```

```text
data.csv/README.md
data.csv/data/train-00000-of-00001.parquet
```

Para converter muitos arquivos, envie-os com um único `hf buckets sync`. Arquivos enviados juntos geralmente chegam como um único evento, de modo que um único Job converte todos eles, até 10.000 arquivos por evento. Consulte [Webhooks](./webhooks#buckets) para o payload completo do bucket e o que acontece acima desse limite.

### O que o script faz

A parte específica de webhooks é a leitura do evento:

```python
event = json.loads(os.environ.get("WEBHOOK_PAYLOAD", "{}"))  # empty when you run the Job yourself
input_bucket = os.environ.get("WEBHOOK_REPO_ID")

for changed_file in event.get("updatedFiles", []):
    if changed_file["action"] != "add":
        continue  # skip deleted files
    path, size = changed_file["path"], changed_file["size"]
    ...  # convert the file (see the full script)
```

Para cada novo arquivo, o script o carrega com `datasets` diretamente do bucket (`hf://buckets/...`). Se o arquivo for maior que um terço do disco livre do Job, ele é transmitido em streaming em vez de ser baixado. O `push_to_hub` então o grava no bucket de saída como Parquet com chunking definido pelo conteúdo, um índice de página e grupos de linhas de no máximo 100 MB.

## Use o padrão para sua própria tarefa

Mantenha a configuração e altere o script. Por exemplo:

- **Remova dados pessoais antes do treinamento.** Colete o texto bruto em um bucket privado, remova informações pessoais com um modelo como [GLiNER2 PII filter](https://huggingface.co/fastino/gliner2-privacy-filter-PII-multi) e envie apenas o texto redigido para o seu conjunto de dados de treinamento.
- **Avalie novos checkpoints.** Um Job de treinamento salva checkpoints em um bucket, e cada novo checkpoint inicia um Job de avaliação. Se um checkpoint for enviado em várias partes, reaja apenas quando um arquivo marcador que você escreve por último aparecer em `updatedFiles`; os eventos podem chegar fora de ordem.
- **Transcreva ou incorpore novos arquivos.** Transforme novas gravações em transcrições ou novos documentos em incorporações para busca.

Ao escrever seu script, decida o que ele faz na primeira execução, quando `WEBHOOK_PAYLOAD` não está definido. Ele pode encerrar, como `optimize-parquet.py` faz, ou realizar trabalho real, como processar os arquivos que já estavam no bucket. Se a primeira execução precisar de um token, por exemplo para ler o bucket ou um script privado, adicione `--secrets HF_TOKEN` ao `hf jobs run`. As execuções via webhook não recebem esse segredo. Elas obtêm seu token do webhook.

## Webhook ou agendamento?

Uma webhook inicia um Job para cada evento, portanto, novos arquivos são processados cerca de um minuto após chegarem. Se não for necessário processá-los com tanta rapidez, um [Job agendado](./jobs-schedule) é uma alternativa: ele é executado a cada hora ou a cada dia e processa tudo que chegou desde a última execução. Isso agrupa o trabalho em menos Jobs, o que ajuda em tarefas de GPU que demoram para iniciar, e evita o limite da webhook de 1.000 acionamentos a cada 24 horas. O script deve, então, encontrar os novos arquivos por conta própria, por exemplo, comparando os buckets de entrada e saída.

