Recuperação: - keyword.py: tokenizador PT (acentos, stopwords, dígitos), BM25 Okapi com índice invertido, e reciprocal_rank_fusion com desempate determinístico - retrieval.py: VectorRetriever e HybridRetriever; fusão por posição, não por nota (cosseno 0..1 e BM25 sem teto são escalas incomparáveis) - identidade de fusão é a coordenada (arquivo,livro,capítulo,versículo): o mesmo versículo chega das duas buscas com distance diferente e o dataclass nunca os igualaria, então o RRF não premiaria o que ambas confirmam - ChatService recebe retriever injetado; referência explícita mantém precedência Contexto: - VerseChunk ganha context (janela de CONTEXT_WINDOW vizinhos por lado, dentro do livro, atravessando capítulos) e embedding_text - store grava a janela como documento e o versículo em verse_text; a UI mostra o versículo citado e o modelo recebe a janela - snapshot() nos dois stores: o BM25 é em memória e o Chroma persiste, então o arranque precisa reconstruir o índice lexical ou a busca degrada em silêncio Motivação medida em 5703 versículos reais: a busca vetorial não liga 'estou com medo do futuro' a 'não temas' (0,19, nível de par sem relação), e e5-small tem faixa de similaridade de só 0,02 — inutilizaria o piso de evidência.
71 lines
2.7 KiB
Bash
71 lines
2.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) ---
|
|
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, fundidos por posição
|
|
# (RRF). MIN_SIMILARITY é o piso do lado vetorial; abaixo dele o trecho só entra
|
|
# se o BM25 o encontrar.
|
|
# ---------------------------------------------------------------------------
|
|
TOP_K=6
|
|
MIN_SIMILARITY=0.35
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 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
|