Spaces:
Sleeping
Sleeping
Fabio Antonini Claude Sonnet 4.6 commited on
Commit ·
fef4e33
1
Parent(s): 65399d4
Add document upload to RAG tab (rag_add_docs + Accordion UI)
Browse filesCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app/grapholab_demo.py +65 -3
app/grapholab_demo.py
CHANGED
|
@@ -1742,6 +1742,52 @@ def _rag_load_docs():
|
|
| 1742 |
print(f"[RAG] Embedding done: {embedded}/{len(_rag_chunks)} chunks indexed")
|
| 1743 |
|
| 1744 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1745 |
def rag_query(question: str) -> str:
|
| 1746 |
if not question or not question.strip():
|
| 1747 |
return ""
|
|
@@ -1799,10 +1845,26 @@ with gr.Blocks() as rag_tab:
|
|
| 1799 |
"## Consulente Forense IA\n"
|
| 1800 |
"Fai domande sulla grafologia forense. Il sistema recupera gli estratti più "
|
| 1801 |
"rilevanti dalla knowledge base e genera una risposta in italiano con "
|
| 1802 |
-
"**Llama 3.2 via Ollama** (locale, nessun dato inviato online).
|
| 1803 |
-
"Per arricchire la knowledge base aggiungi file PDF o DOCX in `data/knowledge/` "
|
| 1804 |
-
"e riavvia l'app. I PDF scansionati vengono trascritti automaticamente con OCR."
|
| 1805 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1806 |
rag_in = gr.Textbox(
|
| 1807 |
label="Domanda",
|
| 1808 |
placeholder="Es: Come si valuta l'inclinazione della scrittura?",
|
|
|
|
| 1742 |
print(f"[RAG] Embedding done: {embedded}/{len(_rag_chunks)} chunks indexed")
|
| 1743 |
|
| 1744 |
|
| 1745 |
+
def rag_add_docs(files) -> str:
|
| 1746 |
+
"""Index uploaded PDF/DOCX files and add them to the live knowledge base."""
|
| 1747 |
+
if not files:
|
| 1748 |
+
return "Nessun file caricato."
|
| 1749 |
+
try:
|
| 1750 |
+
_requests.get(f"{OLLAMA_URL}/api/tags", timeout=3)
|
| 1751 |
+
except Exception:
|
| 1752 |
+
return (
|
| 1753 |
+
"❌ Ollama non raggiungibile — i documenti non possono essere indicizzati.\n"
|
| 1754 |
+
"Avvia `ollama serve` e ricarica."
|
| 1755 |
+
)
|
| 1756 |
+
lines = []
|
| 1757 |
+
for f in files:
|
| 1758 |
+
path = Path(f.name)
|
| 1759 |
+
suffix = path.suffix.lower()
|
| 1760 |
+
try:
|
| 1761 |
+
if suffix == ".pdf":
|
| 1762 |
+
text = _extract_pdf_text(path)
|
| 1763 |
+
elif suffix in (".docx", ".doc"):
|
| 1764 |
+
import docx as _docx
|
| 1765 |
+
doc = _docx.Document(str(path))
|
| 1766 |
+
text = "\n".join(p.text for p in doc.paragraphs)
|
| 1767 |
+
else:
|
| 1768 |
+
lines.append(f"⚠️ `{path.name}` — formato non supportato (solo PDF/DOCX).")
|
| 1769 |
+
continue
|
| 1770 |
+
except Exception as e:
|
| 1771 |
+
lines.append(f"❌ `{path.name}` — errore: {e}")
|
| 1772 |
+
continue
|
| 1773 |
+
|
| 1774 |
+
if not text.strip():
|
| 1775 |
+
lines.append(f"⚠️ `{path.name}` — nessun testo estratto.")
|
| 1776 |
+
continue
|
| 1777 |
+
|
| 1778 |
+
chunks = _chunk_text(text, path.name)
|
| 1779 |
+
embedded = 0
|
| 1780 |
+
for chunk in chunks:
|
| 1781 |
+
emb = _ollama_embed(chunk["text"])
|
| 1782 |
+
if emb is not None:
|
| 1783 |
+
chunk["emb"] = emb
|
| 1784 |
+
embedded += 1
|
| 1785 |
+
_rag_chunks.extend(chunks)
|
| 1786 |
+
lines.append(f"✅ `{path.name}` — {len(chunks)} chunk, {embedded} indicizzati.")
|
| 1787 |
+
|
| 1788 |
+
return "\n".join(lines)
|
| 1789 |
+
|
| 1790 |
+
|
| 1791 |
def rag_query(question: str) -> str:
|
| 1792 |
if not question or not question.strip():
|
| 1793 |
return ""
|
|
|
|
| 1845 |
"## Consulente Forense IA\n"
|
| 1846 |
"Fai domande sulla grafologia forense. Il sistema recupera gli estratti più "
|
| 1847 |
"rilevanti dalla knowledge base e genera una risposta in italiano con "
|
| 1848 |
+
"**Llama 3.2 via Ollama** (locale, nessun dato inviato online)."
|
|
|
|
|
|
|
| 1849 |
)
|
| 1850 |
+
|
| 1851 |
+
with gr.Accordion("📂 Aggiungi documenti alla knowledge base", open=False):
|
| 1852 |
+
gr.Markdown(
|
| 1853 |
+
"Carica uno o più file PDF o DOCX per arricchire la knowledge base. "
|
| 1854 |
+
"I documenti vengono indicizzati immediatamente e restano disponibili "
|
| 1855 |
+
"per tutta la sessione.\n\n"
|
| 1856 |
+
"I PDF scansionati vengono trascritti automaticamente con OCR.\n\n"
|
| 1857 |
+
"*In alternativa, copia i file in `data/knowledge/` per caricarli automaticamente all'avvio.*"
|
| 1858 |
+
)
|
| 1859 |
+
rag_upload = gr.File(
|
| 1860 |
+
label="Documenti (PDF o DOCX)",
|
| 1861 |
+
file_count="multiple",
|
| 1862 |
+
file_types=[".pdf", ".docx", ".doc"],
|
| 1863 |
+
)
|
| 1864 |
+
rag_upload_btn = gr.Button("Indicizza documenti", variant="secondary")
|
| 1865 |
+
rag_upload_status = gr.Markdown(label="Esito indicizzazione")
|
| 1866 |
+
rag_upload_btn.click(rag_add_docs, inputs=rag_upload, outputs=rag_upload_status)
|
| 1867 |
+
|
| 1868 |
rag_in = gr.Textbox(
|
| 1869 |
label="Domanda",
|
| 1870 |
placeholder="Es: Come si valuta l'inclinazione della scrittura?",
|