Skip to content

IA Local com Docker + RTX 3070 Ti

Guia Completo: Ollama + Open WebUI

Stack recomendada para rodar modelos de linguagem localmente com GPU NVIDIA, interface de gerenciamento e suporte a Docker.


Índice

  1. Visão Geral da Stack
  2. Pré-requisitos
  3. Instalação do NVIDIA Container Toolkit
  4. Configuração do Docker Compose
  5. Subindo a Stack
  6. Gerenciando Modelos
  7. Catálogo de Modelos Recomendados
  8. Setup Completo Sugerido
  9. Usando o Open WebUI
  10. Busca na Web com SearXNG
  11. Benchmark Comparativo de Modelos
  12. Transcrição de Áudio com Whisper
  13. Alternativas à Stack Principal
  14. Solução de Problemas
  15. Referências

1. Visão Geral da Stack

A combinação Ollama + Open WebUI é a solução mais madura e recomendada pela comunidade para rodar LLMs localmente com suporte a GPU NVIDIA via Docker.

Componente Função
Ollama Backend responsável por baixar, gerenciar e servir os modelos via API REST
Open WebUI Interface web estilo ChatGPT para interagir com os modelos e gerenciar tudo

Por que essa stack?

  • Suporte nativo a NVIDIA CUDA — ideal para a RTX 3070 Ti (8 GB de VRAM)
  • Catálogo enorme de modelos: Llama 3, Mistral, Gemma, Phi, DeepSeek, Qwen e muito mais
  • Interface completa com histórico de conversas, gerenciamento de modelos, RAG, múltiplos usuários e suporte a plugins
  • Docker Compose simples e bem documentado
  • API compatível com OpenAI — funciona com ferramentas que usam o padrão OpenAI

Capacidade da RTX 3070 Ti

A RTX 3070 Ti possui 8 GB de VRAM, o que permite rodar modelos de até ~8B parâmetros com quantização Q4/Q5 confortavelmente. Modelos maiores (14B+) são possíveis com quantizações mais agressivas (Q2/Q3), mas com impacto na qualidade das respostas.


2. Pré-requisitos

Antes de começar, verifique se você tem o seguinte instalado:

  • Sistema Operacional: Linux (recomendado Ubuntu 22.04+) ou Windows com WSL2
  • Docker: versão 24.0 ou superior
  • Docker Compose: versão 2.x (já incluído no Docker Desktop)
  • Driver NVIDIA: versão 525 ou superior
  • NVIDIA Container Toolkit: necessário para expor a GPU ao Docker (instalação na seção seguinte)

Verificando os pré-requisitos

# Verificar versão do Docker
docker --version

# Verificar versão do Docker Compose
docker compose version

# Verificar driver NVIDIA
nvidia-smi

# Verificar versão do driver (deve ser >= 525)
nvidia-smi --query-gpu=driver_version --format=csv,noheader

3. Instalação do NVIDIA Container Toolkit

O NVIDIA Container Toolkit é essencial para que os containers Docker possam acessar a GPU.

No Ubuntu/Debian

# 1. Adicionar o repositório NVIDIA
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
  | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
  | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
  | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# 2. Instalar o toolkit
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

# 3. Configurar o Docker para usar o runtime NVIDIA
sudo nvidia-ctk runtime configure --runtime=docker

# 4. Reiniciar o Docker
sudo systemctl restart docker

Verificando a instalação

# Deve exibir informações da sua GPU de dentro de um container
docker run --rm --gpus all nvidia/cuda:12.0-base-ubuntu22.04 nvidia-smi

Se a saída exibir os dados da sua RTX 3070 Ti, a configuração está correta.


4. Configuração do Docker Compose

Crie um diretório para o projeto e o arquivo docker-compose.yml:

mkdir ~/ia-local && cd ~/ia-local

Crie o arquivo docker-compose.yml com o seguinte conteúdo:

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - OLLAMA_KEEP_ALIVE=5m
    volumes:
      - ollama_data:/root/.ollama
    ports:
      - "11434:11434"
    restart: unless-stopped

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    depends_on:
      - ollama
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    volumes:
      - open_webui_data:/app/backend/data
    ports:
      - "3000:8080"
    restart: unless-stopped

  searxng:
    image: searxng/searxng:latest
    container_name: searxng
    environment:
      - SEARXNG_BASE_URL=http://localhost:8889
    volumes:
      - ./searxng:/etc/searxng
    ports:
      - "8889:8080"
    restart: unless-stopped

  whisper:
    image: onerahmet/openai-whisper-asr-webservice:latest
    container_name: whisper
    environment:
      - ASR_MODEL=medium
      - ASR_ENGINE=faster_whisper
      - ASR_COMPUTE_TYPE=int8
    volumes:
      - ./whisper/uploads:/tmp/uploads
      - ./whisper/cache:/root/.cache
    ports:
      - "9000:9000"
    restart: unless-stopped

volumes:
  ollama_data:
  open_webui_data:

Nota sobre OLLAMA_KEEP_ALIVE=5m: mantém o modelo carregado na VRAM por 5 minutos após a última resposta. Se uma nova mensagem for enviada antes do tempo expirar, o contador reinicia. Isso evita o tempo de recarregamento em conversas ativas. Use 0 se quiser liberar a VRAM imediatamente após cada resposta (útil quando outros serviços disputam memória).

Estrutura do projeto

~/ia-local/
├── docker-compose.yml
├── searxng/
│   └── settings.yml
├── whisper/
│   ├── cache/
│   └── uploads/
└── transcrever.sh

Os dados dos modelos e do WebUI serão armazenados em volumes Docker. O SearXNG usa um diretório local (./searxng) para facilitar a edição do arquivo de configuração.


5. Subindo a Stack

# Dentro do diretório ~/ia-local
docker compose up -d

Aguarde o download das imagens na primeira execução. Após isso:

Serviço URL
Open WebUI http://localhost:3000
Ollama API http://localhost:11434
SearXNG http://localhost:8889
Whisper API http://localhost:9000

Verificando o status

# Ver status dos containers
docker compose ps

# Ver logs em tempo real
docker compose logs -f

# Ver logs de um serviço específico
docker compose logs -f ollama
docker compose logs -f open-webui

Parando a stack

# Parar sem remover os dados
docker compose stop

# Parar e remover os containers (dados preservados nos volumes)
docker compose down

# Parar, remover containers E volumes (APAGA TODOS OS MODELOS)
docker compose down -v

6. Gerenciando Modelos

Os modelos podem ser gerenciados tanto pela linha de comando quanto diretamente pela interface do Open WebUI.

Via linha de comando

# Baixar um modelo
docker exec -it ollama ollama pull <nome-do-modelo>

# Listar modelos instalados
docker exec -it ollama ollama list

# Remover um modelo
docker exec -it ollama ollama rm <nome-do-modelo>

# Ver informações detalhadas de um modelo
docker exec -it ollama ollama show <nome-do-modelo>

# Rodar um modelo interativamente no terminal
docker exec -it ollama ollama run <nome-do-modelo>

Via Open WebUI

  1. Acesse http://localhost:3000
  2. Vá em Configurações → Modelos
  3. Use o campo de busca para encontrar e baixar modelos diretamente pelo nome
  4. Gerencie modelos instalados (deletar, atualizar) pela mesma tela

Monitorando o uso da GPU durante inferência

# Monitorar uso da GPU em tempo real
watch -n 1 nvidia-smi

# Ou com mais detalhes
nvidia-smi dmon -s u

7. Catálogo de Modelos Recomendados

7.1 Modelos Gerais (indicados no setup básico)

Modelo Parâmetros VRAM aprox. Ideal para
llama3.2:3b 3B ~2,5 GB Respostas rápidas, uso leve
mistral:7b 7B ~5 GB Equilíbrio perfeito entre velocidade e qualidade
llama3.1:8b 8B ~6 GB Uso geral de alta qualidade
deepseek-r1:8b 8B ~6 GB Raciocínio e resolução de problemas
phi4:14b (Q4) 14B ~8 GB Máximo desempenho (no limite da VRAM)

7.2 Raciocínio e Lógica

Modelo VRAM aprox. Observação
deepseek-r1:7b ~5 GB Raciocínio muito superior a modelos comuns do mesmo tamanho
qwq:32b (Q4) ~8 GB Excelente em matemática e lógica; no limite da VRAM
docker exec -it ollama ollama pull deepseek-r1:7b
docker exec -it ollama ollama pull qwq:32b

7.3 Código

Modelo VRAM aprox. Observação
qwen2.5-coder:7b ~5 GB Um dos melhores para código em 8 GB; supera o CodeLlama
codellama:7b ~5 GB Clássico, ótimo para completions estilo Copilot
starcoder2:7b ~5 GB Suporta mais de 600 linguagens
docker exec -it ollama ollama pull qwen2.5-coder:7b
docker exec -it ollama ollama pull codellama:7b
docker exec -it ollama ollama pull starcoder2:7b

7.4 Multilíngue e Português

Modelo VRAM aprox. Observação
qwen2.5:7b ~5 GB Excelente suporte a português; melhor que Llama em tarefas multilíngue
aya:8b ~6 GB Desenvolvido pela Cohere especificamente para multilíngue
docker exec -it ollama ollama pull qwen2.5:7b
docker exec -it ollama ollama pull aya:8b

7.5 Contexto Longo (Documentos)

Modelo VRAM aprox. Observação
gemma2:9b (Q4) ~7 GB Do Google; janela de contexto grande, excelente em seguir instruções
internlm2_5:7b ~5 GB Contexto de até 200k tokens; ideal para analisar documentos extensos
docker exec -it ollama ollama pull gemma2:9b
docker exec -it ollama ollama pull internlm2_5:7b

7.6 Conversação Geral

Modelo VRAM aprox. Observação
neural-chat:7b ~5 GB Otimizado pela Intel para conversação natural
command-r:35b (Q2/Q3) ~8 GB Excelente em RAG e conversação longa; versão muito comprimida
docker exec -it ollama ollama pull neural-chat:7b

7.7 Embeddings (para RAG e busca semântica)

Modelos leves que rodam preferencialmente na CPU. Essenciais para usar o RAG do Open WebUI.

Modelo Observação
nomic-embed-text Leve e eficiente; recomendado como padrão para RAG
mxbai-embed-large Um dos melhores modelos de embedding open source disponíveis
docker exec -it ollama ollama pull nomic-embed-text
docker exec -it ollama ollama pull mxbai-embed-large

7.8 Gemma 4 (Google DeepMind) — Multimodal com Raciocínio

O Gemma 4 é a geração mais recente do Google DeepMind, com suporte a texto e imagem, raciocínio configurável (thinking mode) e variantes MoE (Mixture of Experts) que ativam apenas uma fração dos parâmetros por token — tornando modelos maiores viáveis em hardware limitado.

Requer Ollama atualizado. Se o pull retornar requires a newer version of Ollama, atualize primeiro (ver seção 14).

Tag Tamanho VRAM Parâmetros ativos Ideal para
gemma4:e2b ~7,2 GB ✅ Cabe com folga ~2B Uso rápido e leve
gemma4:e4b ~9,6 GB ⚠️ Offload parcial ~4B Equilíbrio qualidade/velocidade
gemma4:26b ~18 GB ⚠️ Offload VRAM→RAM ~4B ativos Máxima qualidade viável
gemma4:31b ~20 GB ❌ Inviável com 8 GB Requer hardware maior

Recomendação para o setup com RTX 3070 Ti (8 GB VRAM) + 48 GB RAM: use gemma4:26b. Apesar de pesar 18 GB, o Ollama distribui automaticamente as camadas entre VRAM e RAM. A geração é mais lenta do que o e4b, mas a qualidade de raciocínio científico, código e análise de dados é significativamente superior. Ideal para tarefas como doutorado, vibe coding e análise de dados geoespaciais.

# Variante leve (cabe totalmente na VRAM)
docker exec -it ollama ollama pull gemma4:e2b

# Variante intermediária (melhor custo-benefício)
docker exec -it ollama ollama pull gemma4:e4b

# Variante completa (máxima qualidade — recomendada com 48 GB RAM)
docker exec -it ollama ollama pull gemma4:26b

Sobre o tempo de carregamento

O primeiro token de cada conversa demora alguns segundos enquanto o modelo é carregado na VRAM. Com OLLAMA_KEEP_ALIVE=5m, o modelo permanece carregado por 5 minutos de inatividade — o que elimina esse custo em conversas ativas.


8. Setup Completo Sugerido

Para cobrir a maioria dos casos de uso do dia a dia sem sobrecarregar o armazenamento:

# 1. Modelo geral + português (uso cotidiano)
docker exec -it ollama ollama pull qwen2.5:7b

# 2. Código (desenvolvimento)
docker exec -it ollama ollama pull qwen2.5-coder:7b

# 3. Raciocínio (lógica, matemática, análise)
docker exec -it ollama ollama pull deepseek-r1:7b

# 4. Embedding (necessário para o RAG do Open WebUI)
docker exec -it ollama ollama pull nomic-embed-text

Com esses 4 modelos você cobre: conversação geral em português, geração e revisão de código, raciocínio avançado e busca semântica sobre documentos.

Espaço em disco estimado

Modelo Tamanho em disco
qwen2.5:7b ~4,7 GB
qwen2.5-coder:7b ~4,7 GB
deepseek-r1:7b ~4,7 GB
nomic-embed-text ~274 MB
Total ~14,5 GB

9. Usando o Open WebUI

Primeiro acesso

  1. Acesse http://localhost:3000
  2. Crie uma conta de administrador no primeiro acesso
  3. Faça login e explore a interface

Funcionalidades principais

Funcionalidade Como acessar
Conversar com modelos Tela inicial → selecione o modelo no topo
Baixar/gerenciar modelos Configurações → Modelos
RAG (chat com documentos) Nova conversa → ícone de clipe → envie um PDF/TXT
Configurar modelo de embedding Configurações → Documentos → Modelo de Embedding
Criar assistentes personalizados Espaço de Trabalho → Assistentes
Histórico de conversas Painel lateral esquerdo
API Key para integração Configurações → Conta → Chaves de API

Configurando o RAG

Para usar o sistema de RAG (Retrieval-Augmented Generation) — que permite fazer perguntas sobre documentos próprios:

  1. Vá em Configurações → Documentos
  2. Em Modelo de Embedding, selecione nomic-embed-text
  3. Salve as configurações
  4. Em qualquer conversa, clique no ícone de clipe e envie seu documento
  5. O modelo responderá com base no conteúdo do arquivo

10. Busca na Web com SearXNG

Por padrão, os modelos locais não têm acesso à internet. O SearXNG é um mecanismo de busca self-hosted que pode ser integrado ao Open WebUI para permitir que os modelos consultem informações atuais antes de responder.

Isso é essencial para perguntas como "como está o clima hoje?", "qual é a cotação do dólar?" ou qualquer outra que exija dados em tempo real.

Configuração inicial do settings.yml

Antes de subir o container pela primeira vez, crie o arquivo de configuração:

# Criar o diretório
mkdir -p ~/ia-local/searxng

# Gerar o settings.yml a partir da imagem oficial
docker run --rm --entrypoint cat searxng/searxng:latest \
  /usr/local/searxng/searx/settings.yml \
  > ~/ia-local/searxng/settings.yml

# Verificar se foi gerado corretamente
wc -l ~/ia-local/searxng/settings.yml

Em seguida, abra o arquivo e localize a seção search: para habilitar o formato JSON (necessário para integração com o Open WebUI):

nano ~/ia-local/searxng/settings.yml

Encontre e deixe a seção exatamente assim:

search:
  formats:
    - html
    - json

Atenção: Não use sed para editar essa seção — o arquivo YAML é sensível à indentação e o comando pode inserir entradas duplicadas ou mal formatadas, impedindo o container de iniciar. Edite manualmente com nano ou outro editor de texto.

Como alternativa mais simples, você pode substituir todo o conteúdo do arquivo por uma versão mínima que herda as configurações padrão da imagem:

cat > ~/ia-local/searxng/settings.yml << 'EOF'
use_default_settings: true

search:
  formats:
    - html
    - json

server:
  bind_address: "0.0.0.0"
  port: 8080
  secret_key: "troque-por-uma-chave-aleatoria"
EOF

Subindo e verificando o SearXNG

docker compose up -d searxng

# Aguardar alguns segundos e verificar
docker compose ps
docker logs searxng --tail=10

# Testar a busca via API
curl "http://localhost:8889/search?q=clima+brasilia&format=json" | head -c 300

Se retornar um JSON com resultados, o SearXNG está funcionando corretamente.

Integrando ao Open WebUI

  1. Acesse http://localhost:3000
  2. Vá em Avatar → Configurações → Busca na Web
  3. Ative o toggle Habilitar Busca na Web
  4. Selecione o provedor SearXNG
  5. URL: http://searxng:8080 (porta interna do Docker, não a 8889)
  6. Clique em Salvar

A URL interna usa a porta 8080 porque os containers se comunicam pela rede interna do Docker. A porta 8889 é apenas para acesso pelo navegador no host.

Ativando a busca em uma conversa

A busca web não é ativada automaticamente em todas as conversas. Para usá-la:

  1. Na caixa de mensagem, clique no ícone "+" (canto inferior esquerdo)
  2. Ative a opção Busca na Web
  3. O ícone ficará destacado quando ativo
  4. Envie sua pergunta normalmente

Solução de problemas do SearXNG

Sintoma Causa provável Solução
Container em loop de restart settings.yml com YAML inválido Recriar o arquivo manualmente
curl: Failed to connect Container não está rodando docker compose ps e verificar logs
"number_of_results": 0 Nenhum engine retornou resultado Aguardar e tentar novamente
Erro no Open WebUI ao buscar URL incorreta Usar http://searxng:8080 (não localhost)

11. Benchmark Comparativo de Modelos

O Ollama expõe métricas detalhadas de desempenho em cada resposta via API. É possível usar essas métricas para comparar modelos e escolher o mais adequado para cada caso de uso.

Métricas disponíveis

Métrica Descrição
eval_count Número de tokens gerados na resposta
eval_duration Tempo de geração em nanosegundos
load_duration Tempo para carregar o modelo na VRAM
total_duration Tempo total da requisição (carregamento + geração)
tokens/s Velocidade de geração (calculada a partir das anteriores)

O tempo do 1º token tende a ser alto na primeira execução (modelo carregando na VRAM) e próximo de zero nas seguintes, pois o Ollama mantém o modelo em memória por padrão.

Script de benchmark

Salve o script abaixo como benchmark.sh no diretório da stack:

#!/bin/bash

OLLAMA_URL="http://localhost:11434"
PROMPT="Explique o que é inteligência artificial em 3 parágrafos."
RESULTS_FILE="benchmark_results.md"

MODELS=(
  "qwen2.5:7b"
  "deepseek-r1:7b"
  "qwen2.5-coder:7b"
  "mistral:7b"
  "llama3.1:8b"
)

GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

echo -e "${CYAN}=====================================${NC}"
echo -e "${CYAN}   Benchmark de Modelos Ollama       ${NC}"
echo -e "${CYAN}=====================================${NC}"
echo ""

cat > "$RESULTS_FILE" << EOF
# Benchmark de Modelos Ollama
**Data:** $(date '+%d/%m/%Y %H:%M')
**Prompt:** "${PROMPT}"

| Modelo | Tokens gerados | Tempo total (s) | Tokens/s | Tempo 1º token (ms) |
|--------|---------------|-----------------|----------|----------------------|
EOF

for MODEL in "${MODELS[@]}"; do
  echo -e "Testando ${GREEN}${MODEL}${NC}..."

  if ! docker exec ollama ollama list 2>/dev/null | grep -q "^${MODEL}"; then
    echo -e "  ${YELLOW}Modelo não instalado, pulando...${NC}"
    echo "| ${MODEL} | - | - | - | - |" >> "$RESULTS_FILE"
    continue
  fi

  RESPONSE=$(curl -s -X POST "${OLLAMA_URL}/api/generate" \
    -H "Content-Type: application/json" \
    -d "{\"model\": \"${MODEL}\", \"prompt\": \"${PROMPT}\", \"stream\": false}")

  TOTAL_DURATION=$(echo "$RESPONSE" | grep -o '"total_duration":[0-9]*' | cut -d: -f2)
  EVAL_COUNT=$(echo "$RESPONSE"     | grep -o '"eval_count":[0-9]*'     | cut -d: -f2)
  EVAL_DURATION=$(echo "$RESPONSE"  | grep -o '"eval_duration":[0-9]*'  | cut -d: -f2)
  LOAD_DURATION=$(echo "$RESPONSE"  | grep -o '"load_duration":[0-9]*'  | cut -d: -f2)

  TOTAL_S=$(echo "scale=2; ${TOTAL_DURATION:-0} / 1000000000" | bc)
  LOAD_MS=$(echo "scale=0; ${LOAD_DURATION:-0} / 1000000"     | bc)

  if [ -n "$EVAL_COUNT" ] && [ -n "$EVAL_DURATION" ] && [ "$EVAL_DURATION" -gt 0 ]; then
    TPS=$(echo "scale=1; ${EVAL_COUNT} / (${EVAL_DURATION} / 1000000000)" | bc)
  else
    TPS="N/A"
  fi

  echo -e "  Tokens: ${EVAL_COUNT:-N/A} | Total: ${TOTAL_S}s | Velocidade: ${TPS} tok/s"
  echo "| ${MODEL} | ${EVAL_COUNT:-N/A} | ${TOTAL_S} | ${TPS} | ${LOAD_MS} |" >> "$RESULTS_FILE"
done

echo "" >> "$RESULTS_FILE"
echo "_Tempo total = tempo de geração + carregamento do modelo na VRAM_" >> "$RESULTS_FILE"
echo -e "${GREEN}Resultados salvos em: ${YELLOW}${RESULTS_FILE}${NC}"

Como usar

# Tornar executável
chmod +x ~/ia-local/benchmark.sh

# Editar os modelos a testar (variável MODELS no script)
nano ~/ia-local/benchmark.sh

# Executar
cd ~/ia-local
./benchmark.sh

# Ver os resultados
cat benchmark_results.md

Exemplo de saída

| Modelo             | Tokens gerados | Tempo total (s) | Tokens/s | Tempo 1º token (ms) |
|--------------------|---------------|-----------------|----------|----------------------|
| qwen2.5:7b         | 312           | 18.4            | 42.1     | 823                  |
| deepseek-r1:7b     | 489           | 31.2            | 38.7     | 910                  |
| qwen2.5-coder:7b   | 298           | 17.9            | 43.5     | 798                  |
| mistral:7b         | 341           | 20.1            | 40.2     | 856                  |
| llama3.1:8b        | 367           | 23.5            | 37.8     | 944                  |

Dicas para um benchmark mais preciso

  • Execute o benchmark duas vezes e considere apenas a segunda rodada — na primeira, o modelo ainda não está carregado na VRAM
  • Use sempre o mesmo prompt para comparações justas
  • Feche outros programas que consomem VRAM antes de rodar
  • Teste com prompts de diferentes tipos: conversação, código, raciocínio

12. Transcrição de Áudio com Whisper

O faster-whisper é uma implementação otimizada do Whisper da OpenAI, com suporte a aceleração via GPU e modo CPU. É integrado à stack via container Docker e expõe uma API REST para transcrição de arquivos de áudio.

Decisão: GPU ou CPU?

Modo Quando usar Vantagem
GPU (latest-gpu) Transcrições rápidas e pontuais Muito mais rápido
CPU (latest) Arquivos longos ou máquinas com GPU compartilhada Não disputa VRAM com o display e o Ollama

Em sistemas onde a GPU também serve o display (como desktops com monitor conectado), transcrever arquivos longos com GPU pode travar o vídeo e o teclado. Nesses casos, use o modo CPU.

Configuração inicial

Crie os diretórios necessários:

mkdir -p ~/ia-local/whisper/cache
mkdir -p ~/ia-local/whisper/uploads

O serviço já está incluído no docker-compose.yml da seção 4. Para subir:

docker compose up -d whisper
docker logs whisper -f

Aguarde a mensagem Application startup complete. — na primeira execução o modelo medium (~1,5 GB) será baixado automaticamente para ./whisper/cache.

Modelos disponíveis

Modelo Tamanho RAM/VRAM Qualidade Velocidade
tiny ~75 MB ~1 GB Baixa Muito rápida
base ~145 MB ~1 GB Razoável Rápida
small ~465 MB ~2 GB Boa Moderada
medium ~1,5 GB ~5 GB Muito boa Moderada
large-v3 ~3 GB ~10 GB Excelente Lenta

Para uso cotidiano em CPU, medium com int8 oferece o melhor equilíbrio entre qualidade e velocidade.

Testando a API

# Gerar um áudio de teste
ffmpeg -f lavfi -i "sine=frequency=440:duration=3" -ar 16000 -ac 1 /tmp/teste.wav

# Transcrever
curl -X POST "http://localhost:9000/asr?language=pt&output=txt&encode=false" \
  -H "Content-Type: multipart/form-data" \
  -F "audio_file=@/tmp/teste.wav"

Integração com o Open WebUI (microfone ao vivo)

O Open WebUI possui um motor de transcrição embutido (faster-whisper interno) usado para gravação ao vivo via microfone. Para configurá-lo:

  1. Acesse http://localhost:3000
  2. Vá em Avatar → Configurações → Áudio
  3. Em Speech-to-Text Engine, selecione Whisper (Local)
  4. Em STT Model, troque base por medium e clique no ícone de download ⬇
  5. Clique em Salvar

O microfone no chat funciona para gravação ao vivo. Para transcrever arquivos de áudio existentes (ex.: gravações do iPhone), use o script da próxima seção.

Script de transcrição com barra de progresso

O script abaixo aceita qualquer formato de áudio (.m4a, .mp4, .wav, .mp3), divide automaticamente em chunks de 30 minutos e exibe uma barra de progresso. O resultado é salvo em um arquivo .txt com o mesmo nome do áudio.

Salve como ~/ia-local/transcrever.sh:

#!/bin/bash

# Uso: ./transcrever.sh arquivo.m4a [idioma]
ARQUIVO="$1"
IDIOMA="${2:-pt}"
WHISPER_URL="http://localhost:9000/asr"
CHUNK_MIN=30
SAIDA="${ARQUIVO%.*}.txt"
TMP_DIR=$(mktemp -d /tmp/whisper_XXXXXX)

# Funções auxiliares
barra() {
  local ATUAL=$1 TOTAL=$2
  local PERC=$(( ATUAL * 100 / TOTAL ))
  local FEITO=$(( PERC / 5 ))
  local VAZIO=$(( 20 - FEITO ))
  printf "\r  [%-${FEITO}s%${VAZIO}s] %d%% (%d/%d partes)" \
    "$(printf '#%.0s' $(seq 1 $FEITO 2>/dev/null))" "" "$PERC" "$ATUAL" "$TOTAL"
}

limpar() {
  rm -rf "$TMP_DIR"
}
trap limpar EXIT

# Validações
if [ -z "$ARQUIVO" ]; then
  echo "Uso: $0 <arquivo_audio> [idioma]"
  echo "Exemplo: $0 gravacao.m4a pt"
  exit 1
fi

if [ ! -f "$ARQUIVO" ]; then
  echo "Arquivo não encontrado: $ARQUIVO"
  exit 1
fi

# Detectar duração total
echo "Analisando arquivo..."
DURACAO=$(ffprobe -v error -show_entries format=duration \
  -of default=noprint_wrappers=1:nokey=1 "$ARQUIVO" 2>/dev/null | cut -d. -f1)

if [ -z "$DURACAO" ] || [ "$DURACAO" -eq 0 ]; then
  echo "Erro: não foi possível determinar a duração do arquivo."
  exit 1
fi

CHUNK_SEG=$(( CHUNK_MIN * 60 ))
TOTAL_CHUNKS=$(( (DURACAO + CHUNK_SEG - 1) / CHUNK_SEG ))

echo "Duração total : $(( DURACAO / 60 ))min $(( DURACAO % 60 ))s"
echo "Partes        : $TOTAL_CHUNKS (${CHUNK_MIN}min cada)"
echo "Saída         : $SAIDA"
echo ""

# Dividir em chunks e transcrever
> "$SAIDA"
INICIO=0
PARTE=1

while [ "$PARTE" -le "$TOTAL_CHUNKS" ]; do
  barra "$PARTE" "$TOTAL_CHUNKS"

  CHUNK_WAV="$TMP_DIR/parte_$(printf '%03d' $PARTE).wav"

  # Converter chunk para wav 16kHz mono
  ffmpeg -ss "$INICIO" -t "$CHUNK_SEG" -i "$ARQUIVO" \
    -ar 16000 -ac 1 -f wav "$CHUNK_WAV" \
    -y -loglevel quiet 2>/dev/null

  # Transcrever
  RESULTADO=$(curl -s -X POST \
    "${WHISPER_URL}?language=${IDIOMA}&output=txt&encode=false" \
    -H "Content-Type: multipart/form-data" \
    -F "audio_file=@${CHUNK_WAV}")

  echo "$RESULTADO" >> "$SAIDA"

  INICIO=$(( INICIO + CHUNK_SEG ))
  PARTE=$(( PARTE + 1 ))
done

echo ""
echo ""
echo "✓ Transcrição concluída: $SAIDA"
chmod +x ~/ia-local/transcrever.sh

Como usar o script

# Arquivo em português (padrão)
./transcrever.sh gravacao.m4a

# Especificando o idioma
./transcrever.sh lecture.mp4 en

# O resultado será salvo como gravacao.txt ou lecture.txt

Saída durante a transcrição

Analisando arquivo...
Duração total : 92min 14s
Partes        : 4 (30min cada)
Saída         : gravacao.txt

  [####                ] 25% (1/4 partes)

Formatos de áudio suportados

O script converte o áudio via ffmpeg antes de enviar, aceitando qualquer formato que o ffmpeg reconheça. Os mais comuns são m4a (iPhone), mp4, mp3, wav e ogg.

Arquivos do iPhone salvos localmente geralmente são .m4a. Quando compartilhados diretamente (AirDrop, mensagem), podem chegar como .mp4 — ambos funcionam normalmente.

Limpando os logs do Whisper

sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' whisper)

13. Alternativas à Stack Principal

Ferramenta Tipo Prós Contras
LM Studio App desktop Interface polida, fácil de usar Não roda em Docker
LocalAI Backend Docker Compatível com API OpenAI, muito flexível Configuração mais complexa
AnythingLLM App/Docker Focado em RAG, excelente para bases de conhecimento Pode ser integrado ao Ollama
Jan.ai App desktop Open source, minimalista Sem suporte a Docker
Text Generation WebUI Docker Suporta formatos variados (GGUF, GPTQ, AWQ) Interface mais técnica

Usando o AnythingLLM junto com o Ollama

O AnythingLLM pode ser adicionado à stack como interface alternativa focada em documentos:

# Adicione ao docker-compose.yml
  anythingllm:
    image: mintplexlabs/anythingllm:latest
    container_name: anythingllm
    depends_on:
      - ollama
    environment:
      - OLLAMA_BASE_PATH=http://ollama:11434
    volumes:
      - anythingllm_data:/app/server/storage
    ports:
      - "3001:3001"
    restart: unless-stopped

14. Solução de Problemas

GPU não está sendo detectada

# Verificar se o runtime NVIDIA está configurado
docker info | grep -i runtime

# Testar acesso à GPU
docker run --rm --gpus all nvidia/cuda:12.0-base-ubuntu22.04 nvidia-smi

# Se falhar, reconfigurar o runtime
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Modelos rodando na CPU em vez da GPU

# Verificar se o Ollama detectou a GPU
docker exec -it ollama ollama run llama3.2:3b "oi"
docker logs ollama | grep -i gpu

Se aparecer no GPU detected, verifique se o runtime: nvidia está no docker-compose.yml e se o NVIDIA Container Toolkit foi instalado corretamente.

Open WebUI não conecta ao Ollama

# Verificar se ambos os containers estão rodando
docker compose ps

# Testar a API do Ollama diretamente
curl http://localhost:11434/api/tags

# Ver logs do Open WebUI
docker compose logs open-webui

Erro de memória (Out of Memory) ao carregar modelo

  • Use uma versão com quantização menor: ex., troque phi4:14b por phi4:14b-q4_K_M
  • Feche outros programas que consomem VRAM (jogos, outros modelos)
  • Escolha um modelo menor (7B em vez de 14B)

Atualizando as imagens

# Baixar versões mais recentes de todos os serviços
docker compose pull

# Reiniciar com as novas imagens
docker compose up -d

Para atualizar apenas um serviço específico:

# Atualizar só o Ollama (necessário para modelos recentes como o Gemma 4)
docker compose pull ollama
docker compose up -d ollama

# Atualizar só o Open WebUI
docker compose pull open-webui
docker compose up -d open-webui

Importante: O Gemma 4 e outros modelos recentes exigem versões atualizadas do Ollama. Se o pull retornar requires a newer version of Ollama, atualize o container do Ollama antes de tentar novamente.


15. Referências


Documentação gerada em março de 2026. Atualizada em abril de 2026 com Gemma 4, atualização de containers e configuração de KEEP_ALIVE. Versões e disponibilidade de modelos podem variar.