Natural-language queries (Text2Cypher) ====================================== .. tip:: On a ``JenaGraph`` use :doc:`text2sparql`, or :doc:`text2query` to pick the right translator for any backend. .. admonition:: Optional module - **Install:** only on ``Neo4jGraph``: ``pip install "cvcdocdb[graphrag]"`` (``neo4j-graphrag``, Python >= 3.10). Nothing extra on ``NetworkXGraph`` or ``MemgraphGraph``. - **Import:** ``from cvcdocdb import Text2Cypher`` :mod:`cvcdocdb.text2cypher` lets you ask questions in natural language to a cvcdocdb graph. An LLM translates the question to Cypher and the query is run on the graph. The API is the same for every backend, so a script doesn't change when you switch from ``NetworkXGraph`` to ``Neo4jGraph`` or back. The LLM is passed as a *handle* that already carries its own configuration (API key, endpoint, model...): - a plain ``prompt: str -> str`` callable, e.g. a wrapper around an in-house LLM client, or - any object with an ``invoke(prompt)`` method returning an answer with a ``.content`` string (e.g. the ``neo4j_graphrag`` LLM classes). Quick-start ----------- .. code-block:: python from cvcdocdb import Text2Cypher, Text2CypherError def ask(graph, question, llm): """Works unchanged with any backend.""" try: result = Text2Cypher(graph, llm=llm).query(question) except Text2CypherError as exc: print("The LLM produced an unusable query:", exc) return None print(result.cypher) # the Cypher generated by the LLM return result.records # e.g. [{'n': 42}], shaped like graph.query(cypher) ask(graph, "Quantes persones viuen a Caldes d'Estrac el 1905?", llm=lambda prompt: my_client.complete(prompt)) Backends -------- - ``Neo4jGraph`` — delegates to ``neo4j_graphrag``'s ``Text2CypherRetriever``, on the graph's own driver and database (no Neo4j credentials passed again). Needs the optional dependency (Python >= 3.10):: pip install cvcdocdb[graphrag] :attr:`~cvcdocdb.text2cypher.Text2Cypher.retriever` exposes the underlying retriever, e.g. to plug it into a ``neo4j_graphrag`` ``GraphRAG`` pipeline. - ``MemgraphGraph`` — handled by cvcdocdb itself, with no extra dependency (``neo4j_graphrag`` doesn't work with Memgraph: its retriever runs ``CALL dbms.components()`` without ``YIELD``, which Memgraph rejects). The query is checked for write clauses and run with ``graph.query(cypher)``, and the schema is read with plain Cypher (Memgraph has no ``db.schema.*``). ``retriever`` is ``None``. - ``NetworkXGraph`` (or any backend whose ``query()`` accepts Cypher) — handled by cvcdocdb itself, with no extra dependency; the query is run with ``graph.query(cypher)``. ``NetworkXGraph`` evaluates the common read-only Cypher (node/relationship patterns, ``WHERE``, ``WITH``, aggregations, ``ORDER BY``, ``SKIP``/``LIMIT``...) with the same results as Neo4j — see :mod:`cvcdocdb.nx_cypher` for the supported subset. If the LLM generates syntax outside it (variable-length paths, ``UNWIND``, ``CASE``...), :class:`~cvcdocdb.text2cypher.Text2CypherError` is raised instead of returning wrong results. Notes ----- - Only read-only Cypher is executed; anything else raises :class:`~cvcdocdb.text2cypher.Text2CypherError` before running. On Neo4j the query is planned with ``EXPLAIN`` first; on other backends it is checked for write clauses (``CREATE``, ``MERGE``, ``SET``, ``DELETE``...). - The schema shown to the LLM is introspected from the graph (on Neo4j with built-in ``db.schema.*`` procedures, so the APOC plugin is **not** required). It is **the same text on every backend** for the same graph: every label of a node (main and alternative), labels and properties in alphabetical order. Properties starting with ``_`` and cvcdocdb bookkeeping attributes are left out. Pass ``schema=...`` to provide your own schema text, ``examples=[...]`` for few-shot examples, or ``custom_prompt=...`` (with ``{schema}``, ``{examples}`` and ``{query_text}`` placeholders) to replace the prompt. .. automodule:: cvcdocdb.text2cypher :members: :member-order: bysource :show-inheritance: :exclude-members: retriever, cypher, records, metadata