refactor: troca PDF+OCR por corpus USFX em domínio público
- corpus/: Almeida (João Ferreira de Almeida) em USFX, domínio público, 66 livros / 1189 capítulos / 31098 versículos, versionado com SHA-256 - app/corpus.py: parser USFX (texto no tail de <v/>), nomes canônicos dos livros, aliases (abreviaturas e numerais romanos), VerseChunk sem página - indexer: descobre *.xml em CORPUS_DIR, progresso em versículos, lote configurável, manifesto incremental por SHA-256 - remove extraction.py, parallel.py, bible_parser.py, Tesseract e PyMuPDF - campo page removido de Source/SearchResult/StatusResponse e do frontend - embedder: propriedade name; status reporta o embedder em uso, não o do .env - create_app constrói o embedder ANTES do store (o default HashEmbedder do VectorStore impedia o modelo configurado de ser carregado em produção) - fallback do modelo agora aparece em /api/status.errors - torch 2.6.0 + transformers 5.22.1 pinados (transformers 5.x exige torch>=2.6)
This commit is contained in:
1 parent
621679cee5
commit
2043d5ddcf
34 files changed
+34561
-1842
No files matched your search
+4
-5
@@ -6,21 +6,20 @@ export interface Source {
|
||||
book: string;
|
||||
chapter: number;
|
||||
verse: number;
|
||||
page: number;
|
||||
file: string;
|
||||
score: number;
|
||||
}
|
||||
|
||||
export interface Status {
|
||||
state: "ready" | "indexing" | "error";
|
||||
pdfs_total: number;
|
||||
pdfs_indexed: number;
|
||||
sources_total: number;
|
||||
sources_indexed: number;
|
||||
chunks: number;
|
||||
model: string;
|
||||
last_indexed_at: string | null;
|
||||
errors: string[];
|
||||
pages_processed: number;
|
||||
pages_total: number;
|
||||
verses_indexed: number;
|
||||
verses_total: number;
|
||||
current_file: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,7 @@ export function SourcesAccordion({ sources, citations = [] }: SourcesAccordionPr
|
||||
<blockquote key={source.reference} className="sources__item">
|
||||
<cite className="sources__reference">{source.reference}</cite>
|
||||
<p className="sources__text">{source.text}</p>
|
||||
<footer className="sources__meta">
|
||||
página {source.page} · {source.file}
|
||||
</footer>
|
||||
<footer className="sources__meta">{source.file}</footer>
|
||||
</blockquote>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ interface StatusPanelProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* Painel de status da indexação: quantos PDFs foram lidos, quantos vetores
|
||||
* Painel de status da indexação: quantas fontes foram lidas, quantos versículos
|
||||
* estão indexados e um botão para forçar a reindexação.
|
||||
*/
|
||||
export function StatusPanel({ status, onReindex, reindexing }: StatusPanelProps) {
|
||||
@@ -19,6 +19,10 @@ export function StatusPanel({ status, onReindex, reindexing }: StatusPanelProps)
|
||||
? "Indexando"
|
||||
: "Erro";
|
||||
|
||||
const versesTotal = status?.verses_total ?? 0;
|
||||
const versesIndexed = status?.verses_indexed ?? 0;
|
||||
const percent = versesTotal > 0 ? Math.min(100, (versesIndexed / versesTotal) * 100) : 0;
|
||||
|
||||
return (
|
||||
<section className="status" aria-label="Status da indexação">
|
||||
<header className="status__header">
|
||||
@@ -28,15 +32,15 @@ export function StatusPanel({ status, onReindex, reindexing }: StatusPanelProps)
|
||||
|
||||
<dl className="status__grid">
|
||||
<div className="status__item">
|
||||
<dt>PDFs lidos</dt>
|
||||
<dt>Fontes lidas</dt>
|
||||
<dd>
|
||||
{status?.pdfs_indexed ?? 0}
|
||||
{status ? ` / ${status.pdfs_total}` : ""}
|
||||
{status?.sources_indexed ?? 0}
|
||||
{status ? ` / ${status.sources_total}` : ""}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="status__item">
|
||||
<dt>Vetores indexados</dt>
|
||||
<dd>{status?.chunks ?? 0}</dd>
|
||||
<dt>Versículos indexados</dt>
|
||||
<dd>{(status?.chunks ?? 0).toLocaleString("pt-BR")}</dd>
|
||||
</div>
|
||||
<div className="status__item">
|
||||
<dt>Modelo</dt>
|
||||
@@ -47,25 +51,18 @@ export function StatusPanel({ status, onReindex, reindexing }: StatusPanelProps)
|
||||
{status?.state === "indexing" && (
|
||||
<div className="status__progress">
|
||||
<div className="status__progress-label">
|
||||
{status.current_file ? `Lendo ${status.current_file}` : "Lendo PDFs"}
|
||||
{status.pages_total > 0 && ` · ${status.pages_processed}/${status.pages_total} páginas`}
|
||||
{status.current_file ? `Indexando ${status.current_file}` : "Indexando corpus"}
|
||||
{versesTotal > 0 && ` · ${versesIndexed.toLocaleString("pt-BR")}/${versesTotal.toLocaleString("pt-BR")} versículos`}
|
||||
</div>
|
||||
{status.pages_total > 0 && (
|
||||
{versesTotal > 0 && (
|
||||
<div
|
||||
className="status__progress-bar"
|
||||
role="progressbar"
|
||||
aria-valuenow={status.pages_processed}
|
||||
aria-valuenow={versesIndexed}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={status.pages_total}
|
||||
aria-valuemax={versesTotal}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
width: `${Math.min(
|
||||
100,
|
||||
(status.pages_processed / status.pages_total) * 100,
|
||||
)}%`,
|
||||
}}
|
||||
/>
|
||||
<span style={{ width: `${percent}%` }} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -85,7 +82,7 @@ export function StatusPanel({ status, onReindex, reindexing }: StatusPanelProps)
|
||||
onClick={onReindex}
|
||||
disabled={reindexing || state === "indexing"}
|
||||
>
|
||||
{reindexing ? "Reindexando…" : "Reindexar PDFs"}
|
||||
{reindexing ? "Reindexando…" : "Reindexar corpus"}
|
||||
</button>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user