class CypherQueryBuilder: """Builds Cypher queries for Neo4j graph database.""" INPUT_EXAMPLE = """ NodeLabel1: value1, value2 NodeLabel2: value1, value2 """ EXAMPLE_CYPHER = example_cypher = """ CREATE (n1:NodeLabel1 {property1: "row['property1']", property2: "row['property2']"}) CREATE (n2:NodeLabel2 {property1: "row['property1']", property2: "row['property2']"}) CREATE (n1)-[:RelationshipLabel]->(n2); """ PROMPT_TEMPLATE = PromptTemplate( input_variables=["structure", "node_definitions", "relationships", "example"], template=""" Consider the following Node Definitions:n{node_definitions}nn Consider the following Relationships:n{relationships}nn Generate Cypher queries to create nodes and relationships using the node definitions and relationships below. Remember to replace the placeholder values with actual data from the dataset.n Include all the properties in the Node Definitions for each node as defined and create relationships.n Return a single string with each query separated by a semicolon.n Don't include any other text or quotation marks in the response.n Please return only the string containing Cypher queries. Please do not report triple backticks to identify a code block.nn Example Input:n{input}nn Example Output Cypher query:n{cypher} """ ) def __init__(self, llm: Any, logger: logging.Logger = None): self.llm = llm self.logger = logger or logging.getLogger(__name__) # self.chain = LLMChain(llm=llm, prompt=self.PROMPT_TEMPLATE) self.chain = self.PROMPT_TEMPLATE | self.llm def validate_cypher_query(self, query: str) -> bool: """Validate Cypher query syntax using LLM and regex patterns.""" VALIDATION_PROMPT = PromptTemplate( input_variables=["query"], template=""" Validate this Cypher query and return TRUE or FALSE: Query: {query} Rules to check: 1. Valid CREATE statements 2. Proper property formatting 3. Valid relationship syntax 4. No missing parentheses 5. Valid property names 6. Valid relationship types Return only TRUE if query is valid, FALSE if invalid. """ ) try: # Basic pattern validation basic_valid = all(re.search(pattern, query) for pattern in [ r'CREATE (', r'{.*?}', r')-[:.*?]->' ]) if not basic_valid: return False # LLM validation validation_chain = VALIDATION_PROMPT | self.llm result = validation_chain.invoke({"query": query}) # Parse result is_valid = "TRUE" in result.upper() if not is_valid: self.logger.warning(f"LLM validation failed for query: {query}") return is_valid except Exception as e: self.logger.error(f"Validation error: {e}") return False def sanitize_query(self, query: str) -> str: """Sanitize and format Cypher query.""" return (query .strip() .replace('n', ' ') .replace(' ', ' ') .replace("'row[", "row['") .replace("]'", "']")) @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) def build_queries(self, node_definitions: Dict, relationships: List) -> str: """Build Cypher queries with retry logic.""" try: response = self.chain.invoke({ "node_definitions": str(node_definitions), "relationships": str(relationships), "input": self.INPUT_EXAMPLE, "cypher": self.EXAMPLE_CYPHER }) # Get response inside triple backticks if '