Doc Analyzer: Privacy-First Document Analysis con DeepSeek R1

Nel panorama aziendale del 2025, l’analisi documentale attraverso l’intelligenza artificiale è diventata una necessità. Tuttavia, quando si tratta di documenti sensibili, la privacy rimane una preoccupazione primaria. Come possiamo sfruttare la potenza dell’IA mantenendo i dati al sicuro nei nostri sistemi?
Oggi vi presento Doc Analyzer, un progetto nato proprio per rispondere a questa esigenza. Un’applicazione che combina la potenza del modello DeepSeek R1 con l’architettura RAG (Retrieval Augmented Generation) per analizzare documenti in modo completamente locale, senza mai inviare dati sensibili su cloud esterni.
L’Architettura: Privacy by Design
Doc Analyzer è strutturato secondo il principio “privacy by design”. Ogni componente è stato progettato pensando alla sicurezza dei dati come requisito primario, non come feature aggiuntiva. L’applicazione utilizza FastAPI come backend, Gradio per l’interfaccia utente, e una sofisticata pipeline di processamento documenti basata su LangChain.
L’architettura si articola in tre componenti principali che lavorano in sinergia per garantire un’analisi documentale sicura ed efficiente.
PDFProcessor: L’Estrattore Intelligente
Il PDFProcessor è il primo step della nostra pipeline. Questa classe, implementata utilizzando PyMuPDF, si occupa di:
- Gestire l’upload dei documenti PDF in modo sicuro, supportando sia file locali che upload tramite Gradio
- Estrarre il testo mantenendo la formattazione e la struttura del documento
- Implementare una strategia di chunking che preserva il contesto semantico
La parte più interessante del PDFProcessor è la sua gestione dei file temporanei:
def process(self, file_obj):
with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
if hasattr(file_obj, 'name'):
file_path = file_obj.name
else:
content = file_obj.read()
tmp_file.write(content)
file_path = tmp_file.name
try:
loader = PyMuPDFLoader(file_path)
documents = loader.load()
chunks = self.text_splitter.split_documents(documents)
return chunks
finally:
if 'tmp_file' in locals():
os.unlink(file_path)
Questo codice garantisce che i file vengano eliminati dopo l’elaborazione, non lasciando tracce sensibili sul disco.
RAGProcessor: Il Cuore del Sistema
Il RAGProcessor è il componente più sofisticato dell’applicazione. Implementa l’architettura RAG (Retrieval Augmented Generation) in modo ottimizzato per l’uso locale.
A differenza dei modelli linguistici tradizionali che possono generare “allucinazioni” basandosi sulla loro conoscenza generale, il RAGProcessor ancora le sue risposte direttamente al contenuto dei documenti forniti. Questo approccio “grounded” garantisce che le risposte siano sempre basate su informazioni effettivamente presenti nei documenti, riducendo drasticamente il rischio di hallucinations (puoi approfondire qui).
Analizziamo in dettaglio il suo funzionamento:
Inizializzazione e Configurazione
def __init__(self):
self.model_name = os.getenv('DEEPSEEK_MODEL', 'deepseek-r1:14b')
self.chroma_path = os.getenv('CHROMA_DB_PATH', './data/chroma')
self.persist_db = os.getenv('PERSIST_VECTORDB', 'false').lower() == 'true'
self.embeddings = OllamaEmbeddings(
model=self.model_name,
base_url=f"http://{os.getenv('OLLAMA_HOST', 'localhost')}:{os.getenv('OLLAMA_PORT', '11434')}"
)
L’inizializzazione configura il modello DeepSeek e il database vettoriale ChromaDB. La classe supporta sia la persistenza (mantenendo i dati tra le query) che la modalità effimera (o ephemeral) del database (cancellando i dati dopo ogni query), permettendo diverse strategie di privacy.
Gestione del Database Vettoriale
def query(self, question, chunks):
if not chunks:
raise ValueError("No document chunks provided")
if self.vectordb is None:
self.vectordb = Chroma(
persist_directory=self.chroma_path,
embedding_function=self.embeddings
)
if not self.persist_db:
collections = self.vectordb._client.list_collections()
for collection in collections:
self.vectordb._client.delete_collection(collection.name)
Questa parte è cruciale per la privacy: se la persistenza non è attivata, il sistema elimina automaticamente le collezioni precedenti, garantendo che nessun dato rimanga memorizzato tra le sessioni.
Processo di Retrieval
Il cuore del RAG è il processo di retrieval, dove il sistema recupera i chunks più rilevanti per la query:
self.vectordb = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory=self.chroma_path
)
retriever = self.vectordb.as_retriever()
relevant_chunks = retriever.get_relevant_documents(question)
Generazione della Risposta
La generazione della risposta è ottimizzata per il contesto documentale:
context = "\n\n".join([chunk.page_content for chunk in relevant_chunks])
prompt = f"""Based on the following document excerpts, answer the question.
First, identify which parts of the document are relevant to the question.
Then, provide a detailed answer using ONLY the information from these parts.
If the information needed isn't in the excerpts, clearly state this.
Document excerpts: {context}
Question: {question}
Detailed answer:"""
response = client.chat(
model=self.model_name,
messages=[{
"role": "user",
"content": prompt
}]
)
Il prompt è strutturato per massimizzare la precisione e minimizzare le hallucinations, un problema comune nei sistemi RAG.
Interfaccia Utente con Gradio
L’interfaccia utente è implementata con Gradio e integrata in FastAPI:
interface = gr.Interface(
fn=process_and_query,
inputs=[
gr.File(label="Upload a PDF", file_types=[".pdf"]),
gr.Textbox(label="Ask a question about the document")
],
outputs=gr.Textbox(label="Answer"),
title="DocAnalyzer",
description="Analyze PDF documents with DeepSeek R1",
)
Deployment e Configurazione
Il sistema è containerizzato con Docker, utilizzando un’immagine slim ottimizzata come base:
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
poppler-utils \
tesseract-ocr \
libtesseract-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
RUN mkdir -p /app/data/chroma && chmod 777 /app/data/chroma
COPY requirements.txt requirements-dev.txt setup.py ./
COPY src/ ./src/
COPY tests/ ./tests/
RUN pip install --no-cache-dir -r requirements.txt \
&& pip install --no-cache-dir -r requirements-dev.txt \
&& pip install -e .
ENV PYTHONPATH=/app/src
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Casi d’Uso e Performance
Doc Analyzer eccelle in diversi scenari:
- Analisi di Documentazione Legale
- Estrazione di clausole specifiche
- Identificazione di potenziali rischi
- Comparazione di versioni di contratti
- Analisi Tecnica
- Revisione di specifiche tecniche
- Estrazione di requisiti
- Validazione di documentazione
- Compliance e Audit
- Verifica di conformità normativa
- Identificazione di policy violations
- Documentazione di procedure
Le performance sono molto buone: su un MacBook Pro M3 Pro con 18GB di RAM (di cui 4 dedicati a docker), il sistema processa documenti di 100 pagine in meno di 30 secondi, con tempi di risposta alle query sotto i 6 secondi.
Conclusione: Il Futuro dell’Analisi Documentale
Doc Analyzer dimostra che è possibile costruire sistemi di analisi documentale avanzati mantenendo il controllo completo sui dati. L’architettura RAG combinata con DeepSeek R1 offre un’alternativa concreta ai servizi cloud, ideale per organizzazioni con requisiti stringenti di privacy.
Il progetto è open source e in continua evoluzione. Tra gli sviluppi pianificati:
- Supporto per altri tipi di documento
- Integrazione con sistemi di versioning
- Miglioramenti all’interfaccia utente
- Ottimizzazioni delle performance
P.S. Se state cercando di installare DeepSeek R1 in locale, date un’occhiata alla mia guida dedicata: Installare DeepSeek in Locale con Ollama.