Skip to content

Repository files navigation

AX_Ploration

AX_Ploration is an AI-assisted application for querying ALKIS building data (AX_Gebaeude features) using natural language. This project is part of the "Spatial Information Search" course at University of Münster (WiSe 25/26).

Table of Contents

Overview

The system uses a LangGraph-based agent that processes natural language queries in German and converts them into Cypher queries to retrieve building data from a Neo4j database containing Berlin ALKIS data (96,572 buildings, 234 building functions, 12 districts).

Key Technologies:

  • LangGraph for agent workflow orchestration
  • OpenAI GPT-4o for natural language understanding
  • Neo4j for graph database storage
  • FastAPI for REST API with Server-Sent Events streaming
  • React Frontend built with Vite
  • Leaflet for map display
  • Docker for containerized deployment

List of Questions the Application Can Answer

You can find the planned and realized questions for our application here.

Quick Start

Prerequisites

  • Python 3.11+
  • Neo4j database (Aura or local instance)
  • OpenAI API key

Installation

  1. Clone the repository:
git clone <repository-url>
cd AX_Ploration
  1. Install dependencies:
pip install -r requirements.txt
  1. Configure environment variables by creating a .env file:
OPENAI_API_KEY=sk-your-api-key-here
OPENAI_MODEL=gpt-4o
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
NEO4J_URI=bolt://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=your-password-here
LANGSMITH_API_KEY=
LANGSMITH_PROJECT=ax_ploration
API_PORT=8000

Run with Docker (Recommended)

# Build and start the API server
docker-compose up --build

# The API will be available at http://localhost:8000

Run Locally

# Start the API server
python -m backend.api.server

# Start the frontend
cd alkis-frontend
npm run dev

# Or use the CLI directly
python -m backend.scripts.main "Wie viele Gebäude gibt es in Mitte?"

Project Structure

AX_Ploration/
├── frontend/
│   └── sources/          # React app
├── backend/
│   ├── scripts/          # Core agent implementation
│   └── api/              # REST API with streaming support
├── sample-scripts/       # Jupyter notebook examples
├── docker-compose.yml    # Docker deployment configuration
├── Dockerfile            # Container image definition
└── requirements.txt      # Python dependencies

Backend Scripts

The backend/scripts/ directory contains the core LangGraph agent implementation for direct programmatic use.

Command Line Interface

Run queries directly from the command line:

# Basic query
python -m backend.scripts.main "Zeige mir alle Wohngebäude in Mitte"

# Verbose mode (shows processing steps)
python -m backend.scripts.main "Wie viele Schulen gibt es?" --verbose

Programmatic Usage

from backend.scripts.graph import graph
from backend.scripts.main import create_initial_state

# Execute a query
initial_state = create_initial_state("Zeige mir alle Krankenhäuser")
result = graph.invoke(initial_state)

print(result["final_answer"])
print(f"Query Type: {result['query_type']}")
print(f"Results: {len(result['results'])}")

Agent Workflow

The agent processes queries through these stages:

  1. Attribute Identification - Extracts requested building attributes
  2. Embedding Search - Finds matching building functions (if needed)
  3. Query Interpretation - Classifies query type (district/nearby/statistics)
  4. Cypher Generation - Creates appropriate database query
  5. Data Retrieval - Executes query against Neo4j
  6. Spatial Comparison - Performs spatial analysis (for location-based queries)
  7. Answer Generation - Formats natural language response

For detailed documentation, see README.md.

REST API

The backend/api/ directory provides a FastAPI-based REST API with streaming support, enabling real-time query processing updates.

Starting the API Server

Option 1: Docker (Recommended)

docker-compose up --build

Option 2: Local

python -m backend.api.server

Option 3: Custom Configuration

# Set port in .env
echo "API_PORT=5000" >> .env
python -m backend.api.server

API Endpoints

POST /query

Process natural language queries with optional streaming and optional spatial filter.

Request:

{
  "query": "Wie viele Gebäude gibt es in Mitte?",
  "stream": true
}

Response (Streaming mode):

Server-Sent Events stream with incremental updates:

data: {"type": "message", "content": "Identified attributes: ['Gebäudeanzahl']"}

data: {"type": "message", "content": "Query type: district"}

data: {"type": "message", "content": "Generated Cypher query for cypher_district"}

data: {"type": "final", "state": {
  "query": "Wie viele Gebäude gibt es in Mitte?",
  "attributes": ["Gebäudeanzahl"],
  "query_type": "district",
  "cypher_query": "MATCH (b:Building)-[:IN_DISTRICT]->(d:District)...",
  "results": [{"Gebäudeanzahl": 20746}],
  "final_answer": "In Mitte gibt es insgesamt 20.746 Gebäude.",
  "messages": [...]
}}

Response (Non-streaming mode):

Complete AgentState as JSON:

{
  "query": "Wie viele Gebäude gibt es in Mitte?",
  "attributes": ["Gebäudeanzahl"],
  "needs_building_function": false,
  "building_functions": [],
  "query_type": "district",
  "cypher_query": "MATCH (b:Building)-[:IN_DISTRICT]->(d:District)\nWHERE d.Gemeinde_name = 'Mitte'\nRETURN count(b) AS Gebäudeanzahl",
  "results": [{"Gebäudeanzahl": 20746}],
  "final_answer": "In Mitte gibt es insgesamt 20.746 Gebäude.",
  "messages": [...]
}

GET /health

Check API and database connectivity:

curl http://localhost:8000/health

Response:

{
  "status": "healthy",
  "database": "connected"
}

GET /functions

List all available building functions:

curl http://localhost:8000/functions

Frontend Integration

JavaScript Fetch API (Non-streaming)

async function queryBuildings(query) {
  const response = await fetch('http://localhost:8000/query', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: query,
      stream: false
    })
  });
  
  const data = await response.json();
  console.log('Answer:', data.final_answer);
  console.log('Results:', data.results);
  console.log('Results:', data.cypher_query);
  return data;
}

// Usage
queryBuildings('Wie viele Schulen gibt es in Berlin?');

JavaScript EventSource (Streaming)

function streamQuery(query) {
  const messages = [];
  let finalState = null;
  
  const eventSource = new EventSource(
    `http://localhost:8000/query?` + 
    new URLSearchParams({
      query: query,
      stream: 'true'
    })
  );
  
  // Alternative: Use fetch with POST
  fetch('http://localhost:8000/query', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: query,
      stream: true
    })
  }).then(async response => {
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    
    while (true) {
      const {done, value} = await reader.read();
      if (done) break;
      
      const text = decoder.decode(value);
      const lines = text.split('\n');
      
      for (const line of lines) {
        if (line.startsWith('data: ')) {
          const data = JSON.parse(line.slice(6));
          
          if (data.type === 'message') {
            console.log('Progress:', data.content);
            messages.push(data.content);
            // Update UI with progress message
            updateProgressUI(data.content);
          } 
          else if (data.type === 'final') {
            console.log('Final answer:', data.state.final_answer);
            finalState = data.state;
            // Update UI with final results
            displayResults(data.state);
          }
          else if (data.type === 'error') {
            console.error('Error:', data.error);
            displayError(data.error);
          }
        }
      }
    }
  });
}

// Usage
streamQuery('Zeige mir alle Wohngebäude in Mitte');

Docker Deployment

Building and Running

# Build and start in detached mode
docker-compose up -d --build

# View logs
docker-compose logs -f

# Stop the service
docker-compose down

Configuration

The docker-compose.yml uses environment variables from .env: docker-compose.yml

Health Check

The container includes automatic health monitoring:

# Check container health
docker ps

# Manual health check
curl http://localhost:8000/health

Additional Tools

Note: The following directories contain supplementary tools for data preparation and database management. They are not required for running the main application.

db/ and objektartenkatalogExtraction/

Utility scripts for:

  • Loading detailed building data into Neo4j
  • Extracting building function catalogs
  • Database schema inspection and maintenance

These are primarily for data preprocessing and are not needed for regular application use.

About

AX_Ploration is an AI-assisted web application with the purpose to query ALKIS `AX_Gebaude`-Features by natural language. This project is part of the course "Spatial Information Search" at University of Münster in WiSe 25/26.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages