Causa do 'Provedor de LLM indisponível' no ambiente com Ollama local foi externa: OLLAMA_BASE_URL exportada no shell (http://localhost:11434/v1) vence o .env na interpolação do docker-compose, e localhost dentro do container é o próprio container. Nada no app indicava a URL em uso. Dois defeitos de código que tornavam isso indetectável — e um deles produziria a mesma mensagem mesmo com a URL correta: - _BaseProvider criava o httpx.AsyncClient com o atributo de classe (120 s) e as subclasses atribuíam self.timeout depois. O httpx congela o timeout na construção, então os 300 s pedidos pelo Ollama nunca valeram: um primeiro atendimento com modelo frio era cortado em 120 s com exatamente a mensagem 'provedor indisponível'. O timeout agora é passado ao super(). - LLMProviderError de conexão não citava o endereço tentado; o log dizia só 'All connection attempts failed'. Passa a incluir a endpoint, com credenciais user:pass@ redigidas. /api/health expõe llm_endpoint para comparação direta com o .env. README e .env.example documentam a precedência shell > .env, o fato de /v1 ser a superfície OpenAI-compatível (o adaptador usa /api/chat nativo) e a latência medida do primeiro atendimento.
87 lines
3.7 KiB
Bash
87 lines
3.7 KiB
Bash
# ---------------------------------------------------------------------------
|
|
# Pastor Online — configuração
|
|
# Copie este arquivo para `.env` e ajuste os valores:
|
|
# cp .env.example .env
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Porta do frontend no host (http://localhost:8080)
|
|
FRONTEND_PORT=8080
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Provedor de LLM: ollama | openai | groq | anthropic
|
|
# ---------------------------------------------------------------------------
|
|
LLM_PROVIDER=ollama
|
|
|
|
# --- Ollama (local, requer o profile "local": docker compose --profile local up) ---
|
|
# ATENÇÃO: se você tiver OLLAMA_BASE_URL exportada no shell, ela VENCE este
|
|
# arquivo na interpolação do compose. Confira o valor efetivo com:
|
|
# docker compose --profile local config | grep OLLAMA_BASE_URL
|
|
# E o que está em uso com: GET /api/health -> llm_endpoint
|
|
# O adaptador usa a API nativa do Ollama (/api/chat): NÃO acrescente "/v1".
|
|
OLLAMA_BASE_URL=http://ollama:11434
|
|
OLLAMA_MODEL=qwen2.5:1.5b
|
|
|
|
# --- OpenAI ---
|
|
OPENAI_BASE_URL=https://api.openai.com/v1
|
|
OPENAI_MODEL=gpt-4o-mini
|
|
OPENAI_API_KEY=
|
|
|
|
# --- Groq (compatível com a API da OpenAI) ---
|
|
GROQ_BASE_URL=https://api.groq.com/openai/v1
|
|
GROQ_MODEL=llama-3.3-70b-versatile
|
|
GROQ_API_KEY=
|
|
|
|
# --- Anthropic ---
|
|
ANTHROPIC_BASE_URL=https://api.anthropic.com
|
|
ANTHROPIC_MODEL=claude-sonnet-4-5
|
|
ANTHROPIC_API_KEY=
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Embeddings (CPU)
|
|
# paraphrase-multilingual-MiniLM-L12-v2: multilíngue, ~470 MB
|
|
# all-MiniLM-L6-v2: menor e mais rápido, ~90 MB, apenas inglês
|
|
# ---------------------------------------------------------------------------
|
|
EMBEDDING_MODEL=paraphrase-multilingual-MiniLM-L12-v2
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Busca
|
|
# A recuperação é híbrida: similaridade vetorial + BM25 (com stemming), fundidos
|
|
# por posição (RRF).
|
|
#
|
|
# MIN_SIMILARITY é filtro de ruído do lado vetorial, NÃO um detector de assunto
|
|
# fora do tema. Medido no corpus completo: nenhum valor entre 0,30 e 0,50
|
|
# bloqueou uma pergunta off-topic ("como fazer um bolo de chocolate" bate 0,544
|
|
# em Levítico 7:14). Num corpus de 31 mil versículos sempre há algum acima de
|
|
# qualquer limiar; a recusa off-topic é instruída ao modelo no SYSTEM_PROMPT.
|
|
#
|
|
# MAX_KEYWORD_ONLY: posições da resposta que podem ser ocupadas por trechos que
|
|
# só o BM25 achou. A nota BM25 não separa acerto de ruído (Deuteronômio 28:27
|
|
# pontua 1,000 do topo para "como posso perdoar", e o correto Lucas 7:47 fica em
|
|
# 0,716), então o controle é por cota de posições. 0 desliga o lado lexical.
|
|
# ---------------------------------------------------------------------------
|
|
TOP_K=6
|
|
MIN_SIMILARITY=0.35
|
|
MAX_KEYWORD_ONLY=2
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Ingestão do corpus
|
|
# Diretório com os arquivos USFX (*.xml), montado somente-leitura em /data/corpus.
|
|
# INDEX_BATCH_SIZE: versículos gravados no banco vetorial por lote.
|
|
# CONTEXT_WINDOW: vizinhos indexados junto com cada versículo. Um versículo
|
|
# isolado é curto demais para o embedding captar o tema; a referência exibida
|
|
# continua sendo a do versículo central.
|
|
# ---------------------------------------------------------------------------
|
|
# CORPUS_DIR=/data/corpus
|
|
INDEX_BATCH_SIZE=512
|
|
CONTEXT_WINDOW=2
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# API
|
|
# CORS_ORIGINS=http://localhost:8080,http://127.0.0.1:8080
|
|
# REINDEX_TOKEN=troque-por-um-segredo
|
|
# AUTO_INDEX=true
|
|
# ---------------------------------------------------------------------------
|
|
CORS_ORIGINS=http://localhost:8080,http://127.0.0.1:8080
|
|
REINDEX_TOKEN=
|
|
AUTO_INDEX=true
|