Skip to content

Riferimento API

Questo documento fornisce una referenza completa di tutti i modelli di dominio, le interfacce (Protocol) e le eccezioni di SearchMuse.

Modelli di Dominio

SearchQuery

Rappresenta una query di ricerca fornita dall'utente.

@dataclass(frozen=True)
class SearchQuery:
    """
    Una query di ricerca con parametri di configurazione.
    """
    query: str
    """La domanda o query di ricerca (obbligatorio, non vuoto)."""

    max_iterations: int = 3
    """Numero massimo di iterazioni di ricerca e raffinamento (default: 3)."""

    language: str = "it"
    """Codice lingua per i risultati (ISO 639-1, default: "it")."""

    metadata: dict[str, Any] = field(default_factory=dict)
    """Metadata aggiuntivi su questa ricerca."""

    def validate(self) -> None:
        """Valida l'integrità della query."""
        if not self.query or not self.query.strip():
            raise ValueError("query non può essere vuota")
        if self.max_iterations < 1:
            raise ValueError("max_iterations deve essere >= 1")

SearchResult

Rappresenta un singolo risultato di ricerca da una fonte esterna.

@dataclass(frozen=True)
class SearchResult:
    """
    Un risultato di ricerca da un motore di ricerca.
    """
    title: str
    """Titolo del risultato."""

    url: str
    """URL della risorsa."""

    snippet: str
    """Snippet testuale dal motore di ricerca."""

    source: str
    """Sorgente del risultato (es. 'duckduckgo')."""

    retrieved_at: datetime
    """Data e ora del recupero."""

    def is_valid_url(self) -> bool:
        """Verifica se l'URL è valida."""
        return self.url.startswith(("http://", "https://"))

Citation

Rappresenta una citazione tracciata da una fonte specifica.

@dataclass(frozen=True)
class Citation:
    """
    Una citazione con metadata di origine.
    """
    source_url: str
    """URL della fonte della citazione."""

    source_title: str
    """Titolo della fonte."""

    excerpt: str
    """Testo citato dalla fonte (max 500 caratteri)."""

    page_number: int | None = None
    """Numero di pagina (se applicabile)."""

    retrieved_at: datetime = field(default_factory=datetime.now)
    """Data e ora del recupero."""

    def to_markdown(self) -> str:
        """Formatta la citazione in Markdown."""
        return f"[{self.source_title}]({self.source_url})"

IterationResult

Rappresenta i risultati di una singola iterazione.

@dataclass(frozen=True)
class IterationResult:
    """
    Risultati di una iterazione di ricerca e analisi.
    """
    iteration_number: int
    """Numero dell'iterazione (1-based)."""

    refined_query: str | None
    """Query raffinata per la prossima iterazione."""

    search_results: list[SearchResult]
    """Risultati della ricerca di questa iterazione."""

    llm_analysis: str
    """Analisi generata dall'LLM."""

    citations_used: list[Citation]
    """Citations estratte in questa iterazione."""

    def has_results(self) -> bool:
        """Verifica se ci sono risultati."""
        return len(self.search_results) > 0

    def citation_count(self) -> int:
        """Ritorna il numero di citazioni."""
        return len(self.citations_used)

ResearchSession

Rappresenta una sessione di ricerca completa.

@dataclass(frozen=True)
class ResearchSession:
    """
    Una sessione di ricerca completa con tutte le iterazioni.
    """
    session_id: str
    """ID univoco della sessione (UUID)."""

    initial_query: SearchQuery
    """Query iniziale fornita dall'utente."""

    iterations: list[IterationResult]
    """Tutte le iterazioni eseguite."""

    final_answer: str
    """Risposta finale consolidata."""

    total_sources: int
    """Numero totale di fonti uniche utilizzate."""

    created_at: datetime
    """Timestamp creazione sessione."""

    completed_at: datetime | None = None
    """Timestamp completamento sessione."""

    def is_complete(self) -> bool:
        """Verifica se la sessione è completata."""
        return self.completed_at is not None

    def duration(self) -> timedelta | None:
        """Calcola la durata della ricerca."""
        if self.completed_at is None:
            return None
        return self.completed_at - self.created_at

    def all_citations(self) -> list[Citation]:
        """Ritorna tutte le citazioni da tutte le iterazioni."""
        return [c for it in self.iterations for c in it.citations_used]

Interfacce (Protocol)

LLMPort

Interfaccia per i modelli linguistici.

class LLMPort(Protocol):
    """
    Protocollo per i modelli linguistici.
    """

    def generate(self, prompt: str, max_tokens: int = 1000) -> str:
        """
        Genera testo basato sul prompt fornito.

        Args:
            prompt: Il testo del prompt (non vuoto).
            max_tokens: Numero massimo di token da generare.

        Returns:
            Testo generato dal modello.

        Raises:
            LLMException: Se la generazione fallisce.
        """
        ...

    def summarize(
        self,
        text: str,
        max_length: int = 500,
        language: str = "it"
    ) -> str:
        """
        Riassume un testo fornito.

        Args:
            text: Testo da riassumere.
            max_length: Lunghezza massima del riassunto.
            language: Lingua del riassunto.

        Returns:
            Testo riassunto.

        Raises:
            LLMException: Se il riassunto fallisce.
        """
        ...

    def refine_query(
        self,
        current_query: str,
        context: str,
        max_length: int = 100
    ) -> str:
        """
        Affina una query basata sul contesto precedente.

        Args:
            current_query: Query da affinare.
            context: Contesto da usare per il raffinamento.
            max_length: Lunghezza massima della query raffinata.

        Returns:
            Query raffinata.

        Raises:
            LLMException: Se il raffinamento fallisce.
        """
        ...

SearchEnginePort

Interfaccia per i motori di ricerca.

class SearchEnginePort(Protocol):
    """
    Protocollo per i motori di ricerca.
    """

    def search(
        self,
        query: str,
        num_results: int = 10,
        language: str = "it"
    ) -> list[SearchResult]:
        """
        Esegue una ricerca e ritorna i risultati.

        Args:
            query: Query di ricerca.
            num_results: Numero di risultati da ritornare.
            language: Lingua dei risultati.

        Returns:
            Lista di SearchResult ordinata per rilevanza.

        Raises:
            SearchEngineException: Se la ricerca fallisce.
        """
        ...

    def search_with_filters(
        self,
        query: str,
        num_results: int = 10,
        language: str = "it",
        safe_search: bool = True,
        time_range: str | None = None
    ) -> list[SearchResult]:
        """
        Esegue una ricerca con filtri aggiuntivi.

        Args:
            query: Query di ricerca.
            num_results: Numero di risultati.
            language: Lingua dei risultati.
            safe_search: Abilitare safe search.
            time_range: Intervallo temporale ('1w', '1m', '1y').

        Returns:
            Lista di SearchResult filtrati.

        Raises:
            SearchEngineException: Se la ricerca fallisce.
        """
        ...

WebScraperPort

Interfaccia per il web scraping.

class WebScraperPort(Protocol):
    """
    Protocollo per il web scraping.
    """

    def fetch(
        self,
        url: str,
        timeout: int = 10,
        follow_redirects: bool = True
    ) -> str:
        """
        Recupera il contenuto HTML di una URL.

        Args:
            url: URL da recuperare.
            timeout: Timeout in secondi.
            follow_redirects: Seguire i redirect HTTP.

        Returns:
            Contenuto HTML della pagina.

        Raises:
            WebScraperException: Se il fetch fallisce.
        """
        ...

    def extract_text(self, html: str, remove_scripts: bool = True) -> str:
        """
        Estrae testo pulito da HTML.

        Args:
            html: HTML da processare.
            remove_scripts: Rimuovere tag script e style.

        Returns:
            Testo estratto e pulito.

        Raises:
            WebScraperException: Se l'estrazione fallisce.
        """
        ...

RepositoryPort

Interfaccia per la persistenza.

class RepositoryPort(Protocol):
    """
    Protocollo per la persistenza dei dati.
    """

    def save_session(self, session: ResearchSession) -> str:
        """
        Salva una sessione di ricerca.

        Args:
            session: Sessione da salvare.

        Returns:
            session_id della sessione salvata.

        Raises:
            RepositoryException: Se il salvataggio fallisce.
        """
        ...

    def get_session(self, session_id: str) -> ResearchSession | None:
        """
        Recupera una sessione di ricerca.

        Args:
            session_id: ID della sessione da recuperare.

        Returns:
            ResearchSession se trovata, None altrimenti.

        Raises:
            RepositoryException: Se il recupero fallisce.
        """
        ...

    def list_sessions(
        self,
        limit: int = 10,
        offset: int = 0
    ) -> list[ResearchSession]:
        """
        Elenca le sessioni di ricerca.

        Args:
            limit: Numero massimo di risultati.
            offset: Numero di risultati da saltare.

        Returns:
            Lista di ResearchSession ordinate per data decrescente.

        Raises:
            RepositoryException: Se l'elencazione fallisce.
        """
        ...

    def delete_session(self, session_id: str) -> bool:
        """
        Cancella una sessione di ricerca.

        Args:
            session_id: ID della sessione da cancellare.

        Returns:
            True se cancellata, False se non trovata.

        Raises:
            RepositoryException: Se la cancellazione fallisce.
        """
        ...

Enumerazioni

SearchResultSource

Enumera le possibili sorgenti di risultati.

from enum import Enum

class SearchResultSource(Enum):
    """Sorgenti possibili per i risultati di ricerca."""
    DUCKDUCKGO = "duckduckgo"
    GOOGLE = "google"
    BING = "bing"
    WIKIPEDIA = "wikipedia"

ErrorLevel

Livelli di severità degli errori.

from enum import Enum

class ErrorLevel(Enum):
    """Livelli di severità degli errori."""
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"
    CRITICAL = "critical"

Eccezioni

SearchMuseException

Eccezione base per tutte le eccezioni di SearchMuse.

class SearchMuseException(Exception):
    """
    Eccezione base per SearchMuse.
    """
    def __init__(
        self,
        message: str,
        error_code: str | None = None,
        details: dict[str, Any] | None = None
    ):
        super().__init__(message)
        self.error_code = error_code
        self.details = details or {}

DomainException

Eccezione per violazioni di invarianti di dominio.

class DomainException(SearchMuseException):
    """Eccezione sollevata per violazioni di dominio."""
    pass

LLMException

Eccezione per errori della comunicazione con l'LLM.

class LLMException(SearchMuseException):
    """Eccezione sollevata da errori di LLM."""
    pass

class LLMTimeoutException(LLMException):
    """LLM ha superato il timeout."""
    pass

class LLMConnectionException(LLMException):
    """Impossibile connettersi a Ollama."""
    pass

SearchEngineException

Eccezione per errori della comunicazione con il motore di ricerca.

class SearchEngineException(SearchMuseException):
    """Eccezione sollevata da errori di ricerca."""
    pass

class SearchRateLimitException(SearchEngineException):
    """Rate limit raggiunto dal motore di ricerca."""
    pass

WebScraperException

Eccezione per errori del web scraping.

class WebScraperException(SearchMuseException):
    """Eccezione sollevata da errori di scraping."""
    pass

class URLNotReachableException(WebScraperException):
    """URL non raggiungibile."""
    pass

RepositoryException

Eccezione per errori della persistenza.

class RepositoryException(SearchMuseException):
    """Eccezione sollevata da errori di repository."""
    pass

class SessionNotFoundException(RepositoryException):
    """Sessione non trovata nel repository."""
    pass

Utilizzo Tipico

Creazione di una Query

from searchmuse.domain.models import SearchQuery

# Creazione semplice
query = SearchQuery(query="Come funziona la fotosintesi?")

# Con parametri personalizzati
query = SearchQuery(
    query="Ultimi sviluppi in AI",
    max_iterations=5,
    language="en",
    metadata={"user_id": "user123"}
)

# Validazione
query.validate()

Handling Eccezioni

from searchmuse.domain.exceptions import LLMException, SearchEngineException

try:
    results = search_engine.search("query")
except SearchEngineException as e:
    logger.error(f"Errore ricerca: {e.error_code}")
except LLMException as e:
    logger.error(f"Errore LLM: {e.details}")

Versione: 1.0 Ultimo Aggiornamento: Febbraio 2026 Stato: Stabile