feinschliff für pek
This commit is contained in:
parent
e0c4193e36
commit
8e2c4adcb5
20 changed files with 1637 additions and 24 deletions
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "wie viele Projekte in Zürich gibt es?"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "READ",
|
||||||
|
"entity": "Projekt",
|
||||||
|
"parameters": {
|
||||||
|
"location_filter": "Zürich"
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Analysis:**
|
||||||
|
- **Intent**: READ - The user wants to query/count existing projects ("wie viele ... gibt es?" = "how many ... are there?")
|
||||||
|
- **Entity**: Projekt - The user is asking about "Projekte" (projects)
|
||||||
|
- **Parameters**:
|
||||||
|
- `location_filter: "Zürich"` - The user wants to filter projects by location (Zürich). Since Projekt doesn't have direct location fields, this will need to be resolved through the associated Parzellen's kontextGemeinde relationship
|
||||||
|
- **Confidence**: 0.9 - High confidence as the intent and entity are clear, though the query involves a relationship traversal (Projekt → Parzelle → Gemeinde)
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "Erstelle ein neues Projekt in Zürich"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Projekt",
|
||||||
|
"parameters": {
|
||||||
|
"location_filter": "Zürich"
|
||||||
|
},
|
||||||
|
"confidence": 0.85
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Explanation:**
|
||||||
|
- **Intent**: CREATE - The user wants to create a new project ("Erstelle ein neues Projekt")
|
||||||
|
- **Entity**: Projekt - The entity type is clearly specified
|
||||||
|
- **Parameters**:
|
||||||
|
- `location_filter`: "Zürich" - The user mentions "in Zürich" as the location. Since Projekt doesn't have direct location fields (location is stored in associated Parzellen), I'm using `location_filter` to indicate the intended location context. This will need to be handled by creating associated Parzellen with the appropriate `kontextGemeinde` value.
|
||||||
|
- **Confidence**: 0.85 - High confidence in intent and entity, slightly lower because the location reference for a new project is indirect (projects get location through their parcels) and no project name/label was provided.
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "wie viele Projekte in zürich gibt es jetzt?"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "READ",
|
||||||
|
"entity": "Projekt",
|
||||||
|
"parameters": {
|
||||||
|
"location_filter": "zürich"
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Analysis:**
|
||||||
|
- **Intent**: READ - The user wants to query/count existing projects ("wie viele Projekte ... gibt es")
|
||||||
|
- **Entity**: Projekt - The query is about projects ("Projekte")
|
||||||
|
- **Parameters**:
|
||||||
|
- `location_filter`: "zürich" - The user is asking about projects in Zürich. Since Projekt doesn't have direct location fields but location is stored in associated Parzellen (via kontextGemeinde), we use the `location_filter` parameter to indicate this geographic filter needs to be resolved through the Parzelle relationship.
|
||||||
|
- **Confidence**: 0.9 - High confidence. The intent is clear (counting/querying projects), the location is explicitly mentioned, and the temporal indicator "jetzt" (now) suggests current/active projects.
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "wie viele parzellen in zürich gibt es?"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "READ",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"kontextGemeinde": "Zürich"
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Reasoning:**
|
||||||
|
- The user is asking "wie viele parzellen in zürich gibt es?" (how many plots are there in Zürich?)
|
||||||
|
- **Intent**: READ - The user wants to query/read information about existing entities
|
||||||
|
- **Entity**: Parzelle - The user is specifically asking about "parzellen" (plots/parcels)
|
||||||
|
- **Parameters**: The location "Zürich" refers to a municipality (Gemeinde). Since Parzelle has the field `kontextGemeinde` which links to the municipality, this is the appropriate field to use for filtering by location
|
||||||
|
- **Confidence**: 0.9 - High confidence as the intent and entity are clearly stated, though the exact count operation is implicit
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "wie viele parzellen in zürich gibt es?"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "READ",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"kontextGemeinde": "Zürich"
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Reasoning:**
|
||||||
|
- The user is asking "wie viele parzellen in zürich gibt es?" (how many plots are there in Zürich?)
|
||||||
|
- **Intent**: READ - The user wants to query/read information about existing entities
|
||||||
|
- **Entity**: Parzelle - The user is specifically asking about "parzellen" (plots/parcels)
|
||||||
|
- **Parameters**: The location "Zürich" refers to a municipality (Gemeinde). Since Parzelle has the field `kontextGemeinde` which links to the municipality, this is the appropriate field to use for filtering by location
|
||||||
|
- **Confidence**: 0.9 - High confidence as the intent and entity are clearly stated, though the exact count operation is implicit
|
||||||
106
logs/debug/prompts/20251201-161718-013-intentanalysis_prompt.txt
Normal file
106
logs/debug/prompts/20251201-161718-013-intentanalysis_prompt.txt
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "add a new parzelle with these information into the database: Parzellen-Informationen
|
||||||
|
Ausgewählte Parzelle
|
||||||
|
ID:AA1704
|
||||||
|
Nummer:AA1704
|
||||||
|
Name:AA1704
|
||||||
|
EGRID:CH887199917793
|
||||||
|
IdentND:ZH0200000261
|
||||||
|
Kanton:ZH
|
||||||
|
Gemeinde:Zürich
|
||||||
|
Gemeinde-Code:261
|
||||||
|
Fläche:6514.99 m²
|
||||||
|
Zentrum (LV95):2682951.44, 1247622.91
|
||||||
|
Geoportal:
|
||||||
|
Link öffnen
|
||||||
|
Kartenansicht
|
||||||
|
Zentrum:2682951.44, 1247622.91
|
||||||
|
Bounds Min:2682914.00, 1247582.00
|
||||||
|
Bounds Max:2683024.30, 1247667.50"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"id": "AA1704",
|
||||||
|
"label": "AA1704",
|
||||||
|
"kontextGemeinde": "Zürich"
|
||||||
|
},
|
||||||
|
"confidence": 0.75
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Analysis:**
|
||||||
|
|
||||||
|
The user wants to add a new "Parzelle" (plot/parcel) to the database. The command provides extensive information about the parcel, but only a subset can be mapped to the available fields in the **Parzelle** entity definition:
|
||||||
|
|
||||||
|
**Mapped fields:**
|
||||||
|
- `id`: "AA1704" (from ID/Nummer)
|
||||||
|
- `label`: "AA1704" (from Name)
|
||||||
|
- `kontextGemeinde`: "Zürich" (from Gemeinde - will need to be resolved to municipality ID)
|
||||||
|
|
||||||
|
**Unmapped information** (not available in the Parzelle entity schema):
|
||||||
|
- EGRID: CH887199917793
|
||||||
|
- IdentND: ZH0200000261
|
||||||
|
- Kanton: ZH
|
||||||
|
- Gemeinde-Code: 261
|
||||||
|
- Fläche: 6514.99 m²
|
||||||
|
- Zentrum coordinates (LV95): 2682951.44, 1247622.91
|
||||||
|
- Bounds coordinates
|
||||||
|
|
||||||
|
**Confidence reasoning:**
|
||||||
|
The confidence is set to 0.75 because:
|
||||||
|
- The intent (CREATE) is clear
|
||||||
|
- The entity (Parzelle) is explicitly mentioned
|
||||||
|
- However, most of the provided information cannot be stored in the current Parzelle schema
|
||||||
|
- The user may expect all this data to be stored, but the system can only capture id, label, and kontextGemeinde from the provided information
|
||||||
131
logs/debug/prompts/20251201-162158-015-intentanalysis_prompt.txt
Normal file
131
logs/debug/prompts/20251201-162158-015-intentanalysis_prompt.txt
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "erstelle einen neuen parzelleneintrag mit diesen informationen: ID:AA4198
|
||||||
|
Nummer:AA4198
|
||||||
|
Name:AA4198
|
||||||
|
EGRID:CH879177719964
|
||||||
|
IdentND:ZH0200000261
|
||||||
|
Adresse:Steinmühleplatz 3, 8001 Zürich
|
||||||
|
Kanton:ZH
|
||||||
|
Gemeinde:Zürich
|
||||||
|
Gemeinde-Code:261
|
||||||
|
Fläche:1972.83 m²
|
||||||
|
Zentrum (LV95):2682910.35, 1247566.80"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Parzelle", "parameters": {"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
|
||||||
|
Output: {
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"label": "AA1704",
|
||||||
|
"parzellenAliasTags": ["AA1704"],
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{"kategorie": "Swiss Topo", "schluessel": "EGRID", "wert": "CH887199917793"},
|
||||||
|
{"kategorie": "Kanton", "schluessel": "Abkürzung", "wert": "ZH"},
|
||||||
|
{"kategorie": "Gemeinde", "schluessel": "BFS-Nummer", "wert": "261"},
|
||||||
|
{"kategorie": "Parzelle", "schluessel": "Fläche", "wert": "6514.99", "einheit": "m²"},
|
||||||
|
{"kategorie": "Parzelle", "schluessel": "Zentrum_X", "wert": "2682951.44", "crs": "EPSG:2056"},
|
||||||
|
{"kategorie": "Parzelle", "schluessel": "Zentrum_Y", "wert": "1247622.91", "crs": "EPSG:2056"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
Note: Extract structured data from detailed input. Use kontextInformationen for metadata like EGRID, coordinates, area, etc.
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
||||||
|
IMPORTANT EXTRACTION RULES:
|
||||||
|
1. For CREATE operations, extract ALL mentioned data fields from the user input
|
||||||
|
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
|
||||||
|
3. Match field names EXACTLY to the entity definition above
|
||||||
|
4. Convert data types correctly (strings for text, numbers for numeric values)
|
||||||
|
5. Extract coordinates, areas, and other numeric values from text
|
||||||
|
6. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"label": "AA4198",
|
||||||
|
"strasseNr": "Steinmühleplatz 3",
|
||||||
|
"plz": "8001",
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "ID",
|
||||||
|
"wert": "AA4198"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Nummer",
|
||||||
|
"wert": "AA4198"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Swiss Topo",
|
||||||
|
"schluessel": "EGRID",
|
||||||
|
"wert": "CH879177719964"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "IdentND",
|
||||||
|
"wert": "ZH0200000261"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Kanton",
|
||||||
|
"schluessel": "Abkürzung",
|
||||||
|
"wert": "ZH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Gemeinde",
|
||||||
|
"schluessel": "BFS-Nummer",
|
||||||
|
"wert": "261"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Fläche",
|
||||||
|
"wert": "1972.83",
|
||||||
|
"einheit": "m²"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Zentrum_X",
|
||||||
|
"wert": "2682910.35",
|
||||||
|
"crs": "EPSG:2056"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Zentrum_Y",
|
||||||
|
"wert": "1247566.80",
|
||||||
|
"crs": "EPSG:2056"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confidence": 0.95
|
||||||
|
}
|
||||||
|
```
|
||||||
131
logs/debug/prompts/20251201-162358-017-intentanalysis_prompt.txt
Normal file
131
logs/debug/prompts/20251201-162358-017-intentanalysis_prompt.txt
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "erstelle einen neuen parzelleneintrag mit diesen informationen: ID:AA4198
|
||||||
|
Nummer:AA4198
|
||||||
|
Name:AA4198
|
||||||
|
EGRID:CH879177719964
|
||||||
|
IdentND:ZH0200000261
|
||||||
|
Adresse:Steinmühleplatz 3, 8001 Zürich
|
||||||
|
Kanton:ZH
|
||||||
|
Gemeinde:Zürich
|
||||||
|
Gemeinde-Code:261
|
||||||
|
Fläche:1972.83 m²
|
||||||
|
Zentrum (LV95):2682910.35, 1247566.80"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Parzelle", "parameters": {"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
|
||||||
|
Output: {
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"label": "AA1704",
|
||||||
|
"parzellenAliasTags": ["AA1704"],
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{"kategorie": "Swiss Topo", "schluessel": "EGRID", "wert": "CH887199917793"},
|
||||||
|
{"kategorie": "Kanton", "schluessel": "Abkürzung", "wert": "ZH"},
|
||||||
|
{"kategorie": "Gemeinde", "schluessel": "BFS-Nummer", "wert": "261"},
|
||||||
|
{"kategorie": "Parzelle", "schluessel": "Fläche", "wert": "6514.99", "einheit": "m²"},
|
||||||
|
{"kategorie": "Parzelle", "schluessel": "Zentrum_X", "wert": "2682951.44", "crs": "EPSG:2056"},
|
||||||
|
{"kategorie": "Parzelle", "schluessel": "Zentrum_Y", "wert": "1247622.91", "crs": "EPSG:2056"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
Note: Extract structured data from detailed input. Use kontextInformationen for metadata like EGRID, coordinates, area, etc.
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
||||||
|
IMPORTANT EXTRACTION RULES:
|
||||||
|
1. For CREATE operations, extract ALL mentioned data fields from the user input
|
||||||
|
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
|
||||||
|
3. Match field names EXACTLY to the entity definition above
|
||||||
|
4. Convert data types correctly (strings for text, numbers for numeric values)
|
||||||
|
5. Extract coordinates, areas, and other numeric values from text
|
||||||
|
6. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"label": "AA4198",
|
||||||
|
"strasseNr": "Steinmühleplatz 3",
|
||||||
|
"plz": "8001",
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "ID",
|
||||||
|
"wert": "AA4198"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Nummer",
|
||||||
|
"wert": "AA4198"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Swiss Topo",
|
||||||
|
"schluessel": "EGRID",
|
||||||
|
"wert": "CH879177719964"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "IdentND",
|
||||||
|
"wert": "ZH0200000261"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Kanton",
|
||||||
|
"schluessel": "Abkürzung",
|
||||||
|
"wert": "ZH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Gemeinde",
|
||||||
|
"schluessel": "BFS-Nummer",
|
||||||
|
"wert": "261"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Fläche",
|
||||||
|
"wert": "1972.83",
|
||||||
|
"einheit": "m²"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Zentrum_X",
|
||||||
|
"wert": "2682910.35",
|
||||||
|
"crs": "EPSG:2056"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kategorie": "Parzelle",
|
||||||
|
"schluessel": "Zentrum_Y",
|
||||||
|
"wert": "1247566.80",
|
||||||
|
"crs": "EPSG:2056"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confidence": 0.95
|
||||||
|
}
|
||||||
|
```
|
||||||
137
logs/debug/prompts/20251201-162418-019-intentanalysis_prompt.txt
Normal file
137
logs/debug/prompts/20251201-162418-019-intentanalysis_prompt.txt
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
|
||||||
|
Analyze the following user command and extract the intent, entity, and parameters.
|
||||||
|
|
||||||
|
User Command: "erstelle einen neuen parzelleneintrag mit diesen informationen: ID:AA4198
|
||||||
|
Nummer:AA4198
|
||||||
|
Name:AA4198
|
||||||
|
EGRID:CH879177719964
|
||||||
|
IdentND:ZH0200000261
|
||||||
|
Adresse:Steinmühleplatz 3, 8001 Zürich
|
||||||
|
Kanton:ZH
|
||||||
|
Gemeinde:Zürich
|
||||||
|
Gemeinde-Code:261
|
||||||
|
Fläche:1972.83 m²
|
||||||
|
Zentrum (LV95):2682910.35, 1247566.80"
|
||||||
|
|
||||||
|
Available intents:
|
||||||
|
- CREATE: User wants to create a new entity
|
||||||
|
- READ: User wants to read/query entities
|
||||||
|
- UPDATE: User wants to update an existing entity
|
||||||
|
- DELETE: User wants to delete an entity
|
||||||
|
- QUERY: User wants to execute a database query (SQL statements)
|
||||||
|
|
||||||
|
Available entities and their fields:
|
||||||
|
|
||||||
|
**Projekt** (Real estate project):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (project designation/name)
|
||||||
|
- statusProzess: string enum (Eingang, Analyse, Studie, Planung, Baurechtsverfahren, Umsetzung, Archiv)
|
||||||
|
- perimeter: GeoPolylinie (geographic boundary, JSONB)
|
||||||
|
- baulinie: GeoPolylinie (building line, JSONB)
|
||||||
|
- parzellen: List[Parzelle] (plots belonging to project, JSONB)
|
||||||
|
- dokumente: List[Dokument] (documents, JSONB)
|
||||||
|
- kontextInformationen: List[Kontext] (context info, JSONB)
|
||||||
|
|
||||||
|
**Parzelle** (Plot/parcel):
|
||||||
|
- id: string (primary key)
|
||||||
|
- mandateId: string (mandate ID)
|
||||||
|
- label: string (plot designation)
|
||||||
|
- strasseNr: string (street and house number)
|
||||||
|
- plz: string (postal code)
|
||||||
|
- kontextGemeinde: string (municipality ID, Foreign Key to Gemeinde table)
|
||||||
|
- bauzone: string (building zone, e.g. W3, WG2)
|
||||||
|
- az: float (Ausnützungsziffer)
|
||||||
|
- bz: float (Bebauungsziffer)
|
||||||
|
- vollgeschossZahl: int (number of allowed full floors)
|
||||||
|
- gebaeudehoeheMax: float (maximum building height in meters)
|
||||||
|
- laermschutzzone: string (noise protection zone)
|
||||||
|
- hochwasserschutzzone: string (flood protection zone)
|
||||||
|
- grundwasserschutzzone: string (groundwater protection zone)
|
||||||
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
- kontextInformationen: List[Kontext] (metadata - each item has 'thema' and 'inhalt' fields only)
|
||||||
|
|
||||||
|
**Kontext** (Context information for metadata):
|
||||||
|
- thema: string (topic/subject, e.g. "EGRID", "Fläche", "Zentrum")
|
||||||
|
- inhalt: string (content as text, e.g. "CH887199917793", "6514.99 m²", "X: 123, Y: 456")
|
||||||
|
|
||||||
|
**Important relationships:**
|
||||||
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
- Parzelle links to Gemeinde (via kontextGemeinde)
|
||||||
|
- Gemeinde links to Kanton (via id_kanton)
|
||||||
|
- Kanton links to Land (via id_land)
|
||||||
|
- Location queries (city, postal code) should use Parzelle.kontextGemeinde (municipality name will be resolved to ID)
|
||||||
|
- Projekt does NOT have location fields directly - location is stored in associated Parzellen
|
||||||
|
|
||||||
|
Return a JSON object with the following structure:
|
||||||
|
{
|
||||||
|
"intent": "CREATE|READ|UPDATE|DELETE|QUERY",
|
||||||
|
"entity": "Projekt|Parzelle|Dokument|Kanton|Gemeinde|null",
|
||||||
|
"parameters": {
|
||||||
|
// Extracted parameters from user input
|
||||||
|
// For CREATE/UPDATE: include all relevant fields using EXACT field names from above
|
||||||
|
// For READ: include filter criteria using EXACT field names (id, label, plz, kontextGemeinde, etc.)
|
||||||
|
// For DELETE: include entity ID if mentioned
|
||||||
|
// For QUERY: include queryText if SQL is detected
|
||||||
|
// IMPORTANT: Use only field names that exist in the entity definition above
|
||||||
|
},
|
||||||
|
"confidence": 0.0-1.0 // Confidence score for the analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Projekt", "parameters": {"label": "Hauptstrasse 42"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
|
||||||
|
Output: {"intent": "CREATE", "entity": "Parzelle", "parameters": {"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
|
||||||
|
Output: {
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"label": "AA1704",
|
||||||
|
"parzellenAliasTags": ["AA1704"],
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{"thema": "EGRID", "inhalt": "CH887199917793"},
|
||||||
|
{"thema": "Kanton", "inhalt": "ZH"},
|
||||||
|
{"thema": "BFS-Nummer", "inhalt": "261"},
|
||||||
|
{"thema": "Fläche", "inhalt": "6514.99 m²"},
|
||||||
|
{"thema": "Zentrum (LV95)", "inhalt": "X: 2682951.44 m, Y: 1247622.91 m (EPSG:2056)"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
Note: Extract structured data from detailed input. Use kontextInformationen for metadata. Each item has 'thema' (topic) and 'inhalt' (content as text).
|
||||||
|
|
||||||
|
- Input: "Zeige mir alle Projekte"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {}, "confidence": 0.9}
|
||||||
|
|
||||||
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
|
Output: {"intent": "READ", "entity": "Projekt", "parameters": {"location_filter": "Zürich"}, "confidence": 0.9}
|
||||||
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
|
Output: {"intent": "READ", "entity": "Parzelle", "parameters": {"plz": "8000"}, "confidence": 0.95}
|
||||||
|
|
||||||
|
- Input: "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
||||||
|
Output: {"intent": "UPDATE", "entity": "Projekt", "parameters": {"id": "XYZ", "statusProzess": "Planung"}, "confidence": 0.85}
|
||||||
|
|
||||||
|
- Input: "SELECT * FROM Projekt WHERE label = 'Test'"
|
||||||
|
Output: {"intent": "QUERY", "entity": null, "parameters": {"queryText": "SELECT * FROM Projekt WHERE label = 'Test'", "queryType": "sql"}, "confidence": 1.0}
|
||||||
|
|
||||||
|
- Input: "Lösche Parzelle ABC"
|
||||||
|
Output: {"intent": "DELETE", "entity": "Parzelle", "parameters": {"id": "ABC"}, "confidence": 0.9}
|
||||||
|
|
||||||
|
IMPORTANT EXTRACTION RULES:
|
||||||
|
1. For CREATE operations, extract ALL mentioned data fields from the user input
|
||||||
|
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
|
||||||
|
3. Each kontextInformationen item MUST have exactly two fields: 'thema' (topic/subject) and 'inhalt' (content as text string)
|
||||||
|
4. Format kontextInformationen values as readable text strings, including units (e.g., "6514.99 m²", "X: 123, Y: 456")
|
||||||
|
5. Match field names EXACTLY to the entity definition above
|
||||||
|
6. Convert data types correctly (strings for text, numbers for numeric values)
|
||||||
|
7. Extract coordinates, areas, and other numeric values from text
|
||||||
|
8. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {
|
||||||
|
"label": "AA4198",
|
||||||
|
"strasseNr": "Steinmühleplatz 3",
|
||||||
|
"plz": "8001",
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{
|
||||||
|
"thema": "ID",
|
||||||
|
"inhalt": "AA4198"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "Nummer",
|
||||||
|
"inhalt": "AA4198"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "EGRID",
|
||||||
|
"inhalt": "CH879177719964"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "IdentND",
|
||||||
|
"inhalt": "ZH0200000261"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "Kanton",
|
||||||
|
"inhalt": "ZH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "BFS-Nummer",
|
||||||
|
"inhalt": "261"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "Fläche",
|
||||||
|
"inhalt": "1972.83 m²"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"thema": "Zentrum (LV95)",
|
||||||
|
"inhalt": "X: 2682910.35 m, Y: 1247566.80 m (EPSG:2056)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"confidence": 0.95
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -6,7 +6,7 @@ Stateless implementation without session management.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any, List
|
||||||
from modules.datamodels.datamodelUam import User
|
from modules.datamodels.datamodelUam import User
|
||||||
from modules.datamodels.datamodelRealEstate import (
|
from modules.datamodels.datamodelRealEstate import (
|
||||||
Projekt,
|
Projekt,
|
||||||
|
|
@ -72,6 +72,138 @@ async def executeDirectQuery(
|
||||||
|
|
||||||
# ===== AI-basierte Intent-Erkennung und CRUD-Operationen =====
|
# ===== AI-basierte Intent-Erkennung und CRUD-Operationen =====
|
||||||
|
|
||||||
|
def _formatEntitySummary(entity_type: str, items: List[Dict[str, Any]], filters: Dict[str, Any]) -> str:
|
||||||
|
"""
|
||||||
|
Format a human-readable summary of query results.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entity_type: Type of entity (Projekt, Parzelle, etc.)
|
||||||
|
items: List of entity data dictionaries
|
||||||
|
filters: Filter parameters used in the query
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Human-readable summary string
|
||||||
|
"""
|
||||||
|
if not items:
|
||||||
|
return f"Keine {entity_type} gefunden"
|
||||||
|
|
||||||
|
count = len(items)
|
||||||
|
filter_desc = ""
|
||||||
|
if filters:
|
||||||
|
# Format filter description
|
||||||
|
if "kontextGemeinde" in filters:
|
||||||
|
filter_desc = f" in {filters['kontextGemeinde']}"
|
||||||
|
elif "plz" in filters:
|
||||||
|
filter_desc = f" mit PLZ {filters['plz']}"
|
||||||
|
elif "location_filter" in filters:
|
||||||
|
filter_desc = f" in {filters['location_filter']}"
|
||||||
|
|
||||||
|
# Start with count
|
||||||
|
summary = f"Gefunden: {count} {entity_type}{filter_desc}"
|
||||||
|
|
||||||
|
# Add details based on entity type
|
||||||
|
if entity_type == "Parzelle":
|
||||||
|
summary += "\n\nDetails:"
|
||||||
|
for i, item in enumerate(items[:10], 1): # Limit to first 10
|
||||||
|
parts = []
|
||||||
|
|
||||||
|
# Add label or ID
|
||||||
|
if item.get("label"):
|
||||||
|
parts.append(f"Parzelle '{item['label']}'")
|
||||||
|
elif item.get("id"):
|
||||||
|
parts.append(f"Parzelle {item['id'][:8]}...")
|
||||||
|
|
||||||
|
# Add address
|
||||||
|
if item.get("strasseNr"):
|
||||||
|
parts.append(item["strasseNr"])
|
||||||
|
|
||||||
|
# Add PLZ and municipality
|
||||||
|
location_parts = []
|
||||||
|
if item.get("plz"):
|
||||||
|
location_parts.append(item["plz"])
|
||||||
|
if item.get("kontextGemeinde"):
|
||||||
|
location_parts.append(item["kontextGemeinde"])
|
||||||
|
if location_parts:
|
||||||
|
parts.append(" ".join(location_parts))
|
||||||
|
|
||||||
|
# Add building zone
|
||||||
|
if item.get("bauzone"):
|
||||||
|
parts.append(f"Bauzone: {item['bauzone']}")
|
||||||
|
|
||||||
|
summary += f"\n{i}. {', '.join(parts)}"
|
||||||
|
|
||||||
|
if count > 10:
|
||||||
|
summary += f"\n... und {count - 10} weitere"
|
||||||
|
|
||||||
|
elif entity_type == "Projekt":
|
||||||
|
summary += "\n\nDetails:"
|
||||||
|
for i, item in enumerate(items[:10], 1):
|
||||||
|
parts = []
|
||||||
|
|
||||||
|
# Add label
|
||||||
|
if item.get("label"):
|
||||||
|
parts.append(f"'{item['label']}'")
|
||||||
|
|
||||||
|
# Add status
|
||||||
|
if item.get("statusProzess"):
|
||||||
|
parts.append(f"Status: {item['statusProzess']}")
|
||||||
|
|
||||||
|
# Add parcel count
|
||||||
|
parzellen = item.get("parzellen", [])
|
||||||
|
if parzellen:
|
||||||
|
parts.append(f"{len(parzellen)} Parzelle(n)")
|
||||||
|
|
||||||
|
summary += f"\n{i}. {' - '.join(parts)}"
|
||||||
|
|
||||||
|
if count > 10:
|
||||||
|
summary += f"\n... und {count - 10} weitere"
|
||||||
|
|
||||||
|
elif entity_type == "Gemeinde":
|
||||||
|
summary += "\n\nDetails:"
|
||||||
|
for i, item in enumerate(items[:10], 1):
|
||||||
|
parts = []
|
||||||
|
|
||||||
|
if item.get("label"):
|
||||||
|
parts.append(item["label"])
|
||||||
|
if item.get("plz"):
|
||||||
|
parts.append(f"PLZ: {item['plz']}")
|
||||||
|
if item.get("abk"):
|
||||||
|
parts.append(f"Abk: {item['abk']}")
|
||||||
|
|
||||||
|
summary += f"\n{i}. {', '.join(parts)}"
|
||||||
|
|
||||||
|
if count > 10:
|
||||||
|
summary += f"\n... und {count - 10} weitere"
|
||||||
|
|
||||||
|
elif entity_type == "Dokument":
|
||||||
|
summary += "\n\nDetails:"
|
||||||
|
for i, item in enumerate(items[:10], 1):
|
||||||
|
parts = []
|
||||||
|
|
||||||
|
if item.get("label"):
|
||||||
|
parts.append(item["label"])
|
||||||
|
if item.get("dokumentTyp"):
|
||||||
|
parts.append(f"Typ: {item['dokumentTyp']}")
|
||||||
|
if item.get("quelle"):
|
||||||
|
parts.append(f"Quelle: {item['quelle']}")
|
||||||
|
|
||||||
|
summary += f"\n{i}. {', '.join(parts)}"
|
||||||
|
|
||||||
|
if count > 10:
|
||||||
|
summary += f"\n... und {count - 10} weitere"
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Generic format for other entity types
|
||||||
|
if count <= 5:
|
||||||
|
summary += "\n\nDetails:"
|
||||||
|
for i, item in enumerate(items, 1):
|
||||||
|
label = item.get("label") or item.get("id", "")
|
||||||
|
if label:
|
||||||
|
summary += f"\n{i}. {label}"
|
||||||
|
|
||||||
|
return summary
|
||||||
|
|
||||||
|
|
||||||
async def processNaturalLanguageCommand(
|
async def processNaturalLanguageCommand(
|
||||||
currentUser: User,
|
currentUser: User,
|
||||||
userInput: str,
|
userInput: str,
|
||||||
|
|
@ -117,13 +249,82 @@ async def processNaturalLanguageCommand(
|
||||||
parameters=intentAnalysis.get("parameters", {}),
|
parameters=intentAnalysis.get("parameters", {}),
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
# Build user-friendly response
|
||||||
|
response = {
|
||||||
"success": True,
|
"success": True,
|
||||||
"intent": intentAnalysis["intent"],
|
"intent": intentAnalysis["intent"],
|
||||||
"entity": intentAnalysis.get("entity"),
|
"entity": intentAnalysis.get("entity"),
|
||||||
"result": result,
|
"result": result,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add human-readable summary for operations
|
||||||
|
if intentAnalysis["intent"] == "CREATE" and isinstance(result, dict):
|
||||||
|
# Add confirmation message for CREATE operations
|
||||||
|
operation_result = result.get("result")
|
||||||
|
if isinstance(operation_result, dict):
|
||||||
|
entity_name = intentAnalysis.get('entity', 'Eintrag')
|
||||||
|
label = operation_result.get("label", operation_result.get("id", ""))
|
||||||
|
|
||||||
|
# Build detailed message
|
||||||
|
msg_parts = [f"✅ {entity_name} '{label}' erfolgreich erstellt"]
|
||||||
|
|
||||||
|
if entity_name == "Parzelle":
|
||||||
|
if operation_result.get("plz"):
|
||||||
|
msg_parts.append(f"PLZ: {operation_result['plz']}")
|
||||||
|
if operation_result.get("kontextGemeinde"):
|
||||||
|
msg_parts.append(f"Gemeinde: {operation_result['kontextGemeinde']}")
|
||||||
|
if operation_result.get("bauzone"):
|
||||||
|
msg_parts.append(f"Bauzone: {operation_result['bauzone']}")
|
||||||
|
|
||||||
|
kontext_items = operation_result.get("kontextInformationen", [])
|
||||||
|
if kontext_items:
|
||||||
|
msg_parts.append(f"\n📋 {len(kontext_items)} Kontextinformationen gespeichert:")
|
||||||
|
for kontext in kontext_items[:5]: # Show first 5
|
||||||
|
thema = kontext.get("thema", "")
|
||||||
|
inhalt = kontext.get("inhalt", "")
|
||||||
|
if thema and inhalt:
|
||||||
|
msg_parts.append(f" • {thema}: {inhalt}")
|
||||||
|
if len(kontext_items) > 5:
|
||||||
|
msg_parts.append(f" • ... und {len(kontext_items) - 5} weitere")
|
||||||
|
|
||||||
|
elif entity_name == "Projekt":
|
||||||
|
if operation_result.get("statusProzess"):
|
||||||
|
msg_parts.append(f"Status: {operation_result['statusProzess']}")
|
||||||
|
parzellen = operation_result.get("parzellen", [])
|
||||||
|
if parzellen:
|
||||||
|
msg_parts.append(f"{len(parzellen)} Parzelle(n)")
|
||||||
|
|
||||||
|
response["message"] = "\n".join(msg_parts)
|
||||||
|
|
||||||
|
elif intentAnalysis["intent"] == "READ" and isinstance(result, dict):
|
||||||
|
operation_result = result.get("result")
|
||||||
|
if isinstance(operation_result, list):
|
||||||
|
response["count"] = len(operation_result)
|
||||||
|
entity_name = intentAnalysis.get('entity', 'Einträge')
|
||||||
|
|
||||||
|
if len(operation_result) == 0:
|
||||||
|
# Provide helpful message for empty results
|
||||||
|
filter_info = intentAnalysis.get('parameters', {})
|
||||||
|
if filter_info:
|
||||||
|
filter_desc = ", ".join([f"{k}={v}" for k, v in filter_info.items()])
|
||||||
|
response["message"] = f"Keine {entity_name} gefunden mit Filter: {filter_desc}. Möglicherweise sind noch keine Daten vorhanden oder der Filter ist zu spezifisch."
|
||||||
|
else:
|
||||||
|
response["message"] = f"Keine {entity_name} vorhanden. Erstellen Sie zuerst neue Einträge."
|
||||||
|
else:
|
||||||
|
# Create detailed summary based on entity type
|
||||||
|
response["message"] = _formatEntitySummary(
|
||||||
|
entity_name,
|
||||||
|
operation_result,
|
||||||
|
intentAnalysis.get('parameters', {})
|
||||||
|
)
|
||||||
|
elif isinstance(operation_result, dict):
|
||||||
|
response["count"] = 1
|
||||||
|
# Format single entity
|
||||||
|
entity_name = intentAnalysis.get('entity', 'Eintrag')
|
||||||
|
response["message"] = _formatEntitySummary(entity_name, [operation_result], {})
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error processing natural language command: {str(e)}", exc_info=True)
|
logger.error(f"Error processing natural language command: {str(e)}", exc_info=True)
|
||||||
raise
|
raise
|
||||||
|
|
@ -187,6 +388,11 @@ Available entities and their fields:
|
||||||
- parzelleBebaut: JaNein enum (is plot built)
|
- parzelleBebaut: JaNein enum (is plot built)
|
||||||
- parzelleErschlossen: JaNein enum (is plot developed)
|
- parzelleErschlossen: JaNein enum (is plot developed)
|
||||||
- parzelleHanglage: JaNein enum (is plot on slope)
|
- parzelleHanglage: JaNein enum (is plot on slope)
|
||||||
|
- kontextInformationen: List[Kontext] (metadata - each item has 'thema' and 'inhalt' fields only)
|
||||||
|
|
||||||
|
**Kontext** (Context information for metadata):
|
||||||
|
- thema: string (topic/subject, e.g. "EGRID", "Fläche", "Zentrum")
|
||||||
|
- inhalt: string (content as text, e.g. "CH887199917793", "6514.99 m²", "X: 123, Y: 456")
|
||||||
|
|
||||||
**Important relationships:**
|
**Important relationships:**
|
||||||
- Projekte contain Parzellen (projects have plots)
|
- Projekte contain Parzellen (projects have plots)
|
||||||
|
|
@ -215,12 +421,35 @@ Examples:
|
||||||
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
- Input: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
||||||
Output: {{"intent": "CREATE", "entity": "Projekt", "parameters": {{"label": "Hauptstrasse 42"}}, "confidence": 0.95}}
|
Output: {{"intent": "CREATE", "entity": "Projekt", "parameters": {{"label": "Hauptstrasse 42"}}, "confidence": 0.95}}
|
||||||
|
|
||||||
|
- Input: "Erstelle eine Parzelle mit Label 123, PLZ 8000, Gemeinde Zürich, Bauzone W3"
|
||||||
|
Output: {{"intent": "CREATE", "entity": "Parzelle", "parameters": {{"label": "123", "plz": "8000", "kontextGemeinde": "Zürich", "bauzone": "W3"}}, "confidence": 0.95}}
|
||||||
|
|
||||||
|
- Input: "Parzellen-Informationen: ID:AA1704, Nummer:AA1704, EGRID:CH887199917793, Kanton:ZH, Gemeinde:Zürich, Gemeinde-Code:261, Fläche:6514.99 m², Zentrum:2682951.44,1247622.91"
|
||||||
|
Output: {{
|
||||||
|
"intent": "CREATE",
|
||||||
|
"entity": "Parzelle",
|
||||||
|
"parameters": {{
|
||||||
|
"label": "AA1704",
|
||||||
|
"parzellenAliasTags": ["AA1704"],
|
||||||
|
"kontextGemeinde": "Zürich",
|
||||||
|
"kontextInformationen": [
|
||||||
|
{{"thema": "EGRID", "inhalt": "CH887199917793"}},
|
||||||
|
{{"thema": "Kanton", "inhalt": "ZH"}},
|
||||||
|
{{"thema": "BFS-Nummer", "inhalt": "261"}},
|
||||||
|
{{"thema": "Fläche", "inhalt": "6514.99 m²"}},
|
||||||
|
{{"thema": "Zentrum (LV95)", "inhalt": "X: 2682951.44 m, Y: 1247622.91 m (EPSG:2056)"}}
|
||||||
|
]
|
||||||
|
}},
|
||||||
|
"confidence": 0.9
|
||||||
|
}}
|
||||||
|
Note: Extract structured data from detailed input. Use kontextInformationen for metadata. Each item has 'thema' (topic) and 'inhalt' (content as text).
|
||||||
|
|
||||||
- Input: "Zeige mir alle Projekte"
|
- Input: "Zeige mir alle Projekte"
|
||||||
Output: {{"intent": "READ", "entity": "Projekt", "parameters": {{}}, "confidence": 0.9}}
|
Output: {{"intent": "READ", "entity": "Projekt", "parameters": {{}}, "confidence": 0.9}}
|
||||||
|
|
||||||
- Input: "Zeige mir Projekte in Zürich"
|
- Input: "Zeige mir Projekte in Zürich" or "Wie viele Projekte in Zürich"
|
||||||
Output: {{"intent": "READ", "entity": "Parzelle", "parameters": {{"kontextGemeinde": "Zürich"}}, "confidence": 0.9}}
|
Output: {{"intent": "READ", "entity": "Projekt", "parameters": {{"location_filter": "Zürich"}}, "confidence": 0.9}}
|
||||||
Note: Location queries should query Parzelle, not Projekt directly
|
Note: For project location queries, use Projekt entity with location_filter parameter
|
||||||
|
|
||||||
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
- Input: "Zeige mir Parzellen mit PLZ 8000"
|
||||||
Output: {{"intent": "READ", "entity": "Parzelle", "parameters": {{"plz": "8000"}}, "confidence": 0.95}}
|
Output: {{"intent": "READ", "entity": "Parzelle", "parameters": {{"plz": "8000"}}, "confidence": 0.95}}
|
||||||
|
|
@ -233,6 +462,16 @@ Examples:
|
||||||
|
|
||||||
- Input: "Lösche Parzelle ABC"
|
- Input: "Lösche Parzelle ABC"
|
||||||
Output: {{"intent": "DELETE", "entity": "Parzelle", "parameters": {{"id": "ABC"}}, "confidence": 0.9}}
|
Output: {{"intent": "DELETE", "entity": "Parzelle", "parameters": {{"id": "ABC"}}, "confidence": 0.9}}
|
||||||
|
|
||||||
|
IMPORTANT EXTRACTION RULES:
|
||||||
|
1. For CREATE operations, extract ALL mentioned data fields from the user input
|
||||||
|
2. Use kontextInformationen array for metadata that doesn't have dedicated fields (EGRID, BFS numbers, area, coordinates, etc.)
|
||||||
|
3. Each kontextInformationen item MUST have exactly two fields: 'thema' (topic/subject) and 'inhalt' (content as text string)
|
||||||
|
4. Format kontextInformationen values as readable text strings, including units (e.g., "6514.99 m²", "X: 123, Y: 456")
|
||||||
|
5. Match field names EXACTLY to the entity definition above
|
||||||
|
6. Convert data types correctly (strings for text, numbers for numeric values)
|
||||||
|
7. Extract coordinates, areas, and other numeric values from text
|
||||||
|
8. When multiple values are mentioned for the same concept (ID, Nummer, Name), use the most relevant one for 'label' and put alternatives in parzellenAliasTags
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -335,15 +574,56 @@ async def executeIntentBasedOperation(
|
||||||
|
|
||||||
elif entity == "Parzelle":
|
elif entity == "Parzelle":
|
||||||
# Create Parzelle from parameters
|
# Create Parzelle from parameters
|
||||||
parzelle = Parzelle(
|
# Import Kontext for kontextInformationen
|
||||||
mandateId=currentUser.mandateId,
|
from modules.datamodels.datamodelRealEstate import Kontext, GeoPolylinie
|
||||||
label=parameters.get("label", ""),
|
|
||||||
strasseNr=parameters.get("strasseNr"),
|
# Build parzelle data with all extracted parameters
|
||||||
plz=parameters.get("plz"),
|
parzelle_data = {
|
||||||
bauzone=parameters.get("bauzone"),
|
"mandateId": currentUser.mandateId,
|
||||||
kontextGemeinde=parameters.get("kontextGemeinde"),
|
"label": parameters.get("label", ""),
|
||||||
)
|
}
|
||||||
|
|
||||||
|
# Add optional fields if present
|
||||||
|
optional_fields = [
|
||||||
|
"parzellenAliasTags", "eigentuemerschaft", "strasseNr", "plz",
|
||||||
|
"bauzone", "az", "bz", "vollgeschossZahl", "anrechenbarDachgeschoss",
|
||||||
|
"anrechenbarUntergeschoss", "gebaeudehoeheMax", "kontextGemeinde",
|
||||||
|
"regelnGrenzabstand", "regelnMehrlaengenzuschlag", "regelnMehrhoehenzuschlag",
|
||||||
|
"parzelleBebaut", "parzelleErschlossen", "parzelleHanglage",
|
||||||
|
"laermschutzzone", "hochwasserschutzzone", "grundwasserschutzzone"
|
||||||
|
]
|
||||||
|
|
||||||
|
for field in optional_fields:
|
||||||
|
if field in parameters and parameters[field] is not None:
|
||||||
|
parzelle_data[field] = parameters[field]
|
||||||
|
|
||||||
|
# Handle complex objects
|
||||||
|
if "perimeter" in parameters and parameters["perimeter"]:
|
||||||
|
parzelle_data["perimeter"] = GeoPolylinie(**parameters["perimeter"])
|
||||||
|
|
||||||
|
if "baulinie" in parameters and parameters["baulinie"]:
|
||||||
|
parzelle_data["baulinie"] = GeoPolylinie(**parameters["baulinie"])
|
||||||
|
|
||||||
|
# Handle kontextInformationen (convert dicts to Kontext objects)
|
||||||
|
if "kontextInformationen" in parameters and parameters["kontextInformationen"]:
|
||||||
|
kontext_list = []
|
||||||
|
for kontext_data in parameters["kontextInformationen"]:
|
||||||
|
if isinstance(kontext_data, dict):
|
||||||
|
# Ensure only thema and inhalt are passed (Kontext model only has these fields)
|
||||||
|
kontext_obj = Kontext(
|
||||||
|
thema=kontext_data.get("thema", ""),
|
||||||
|
inhalt=kontext_data.get("inhalt", "")
|
||||||
|
)
|
||||||
|
kontext_list.append(kontext_obj)
|
||||||
|
else:
|
||||||
|
kontext_list.append(kontext_data)
|
||||||
|
parzelle_data["kontextInformationen"] = kontext_list
|
||||||
|
|
||||||
|
parzelle = Parzelle(**parzelle_data)
|
||||||
created = realEstateInterface.createParzelle(parzelle)
|
created = realEstateInterface.createParzelle(parzelle)
|
||||||
|
|
||||||
|
logger.info(f"Created Parzelle '{created.label}' with {len(created.kontextInformationen)} context items")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"operation": "CREATE",
|
"operation": "CREATE",
|
||||||
"entity": "Parzelle",
|
"entity": "Parzelle",
|
||||||
|
|
@ -438,17 +718,67 @@ async def executeIntentBasedOperation(
|
||||||
k: v for k, v in parameters.items()
|
k: v for k, v in parameters.items()
|
||||||
if k != "id" and k in validProjektFields
|
if k != "id" and k in validProjektFields
|
||||||
}
|
}
|
||||||
# Warn about invalid fields
|
|
||||||
invalidFields = {k: v for k, v in parameters.items() if k not in validProjektFields and k != "id"}
|
|
||||||
if invalidFields:
|
|
||||||
logger.warning(f"Invalid filter fields for Projekt ignored: {list(invalidFields.keys())}")
|
|
||||||
logger.info("Note: Location queries should use Parzelle entity, not Projekt")
|
|
||||||
|
|
||||||
|
# Handle location_filter specially (filter projects by parcel location)
|
||||||
|
location_filter = parameters.get("location_filter")
|
||||||
|
|
||||||
|
# Get all projects first
|
||||||
projekte = realEstateInterface.getProjekte(recordFilter=recordFilter if recordFilter else None)
|
projekte = realEstateInterface.getProjekte(recordFilter=recordFilter if recordFilter else None)
|
||||||
|
|
||||||
|
# If location filter is present, filter by parcels in that location
|
||||||
|
if location_filter:
|
||||||
|
logger.info(f"Filtering projects by location: {location_filter}")
|
||||||
|
|
||||||
|
# Try to resolve location to Gemeinde ID for UUID comparison
|
||||||
|
location_id = None
|
||||||
|
try:
|
||||||
|
# Check if it's already a UUID
|
||||||
|
import re
|
||||||
|
uuid_pattern = re.compile(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', re.IGNORECASE)
|
||||||
|
if not uuid_pattern.match(location_filter):
|
||||||
|
# Try to resolve name to ID
|
||||||
|
gemeinde_records = realEstateInterface.getGemeinden(recordFilter={"label": location_filter})
|
||||||
|
if gemeinde_records:
|
||||||
|
location_id = gemeinde_records[0].id
|
||||||
|
logger.debug(f"Resolved location '{location_filter}' to ID '{location_id}'")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Could not resolve location filter: {e}")
|
||||||
|
|
||||||
|
filtered_projekte = []
|
||||||
|
|
||||||
|
for projekt in projekte:
|
||||||
|
# Check if any parcel in the project matches the location
|
||||||
|
for parzelle in projekt.parzellen:
|
||||||
|
# Check kontextGemeinde (both UUID and string), plz, or strasseNr for location match
|
||||||
|
location_lower = location_filter.lower()
|
||||||
|
matches = False
|
||||||
|
|
||||||
|
# Check if kontextGemeinde matches (as UUID or string)
|
||||||
|
if parzelle.kontextGemeinde:
|
||||||
|
if (parzelle.kontextGemeinde == location_id or # UUID match
|
||||||
|
parzelle.kontextGemeinde == location_filter or # Exact match
|
||||||
|
location_lower in parzelle.kontextGemeinde.lower()): # Partial string match
|
||||||
|
matches = True
|
||||||
|
|
||||||
|
# Check PLZ or address
|
||||||
|
if not matches and (
|
||||||
|
(parzelle.plz and location_lower in parzelle.plz) or
|
||||||
|
(parzelle.strasseNr and location_lower in parzelle.strasseNr.lower())
|
||||||
|
):
|
||||||
|
matches = True
|
||||||
|
|
||||||
|
if matches:
|
||||||
|
filtered_projekte.append(projekt)
|
||||||
|
break # Found a matching parcel, no need to check more
|
||||||
|
|
||||||
|
projekte = filtered_projekte
|
||||||
|
logger.info(f"Found {len(projekte)} projects in location '{location_filter}'")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"operation": "READ",
|
"operation": "READ",
|
||||||
"entity": "Projekt",
|
"entity": "Projekt",
|
||||||
"result": [p.model_dump() for p in projekte]
|
"result": [p.model_dump() for p in projekte],
|
||||||
|
"count": len(projekte)
|
||||||
}
|
}
|
||||||
elif entity == "Parzelle":
|
elif entity == "Parzelle":
|
||||||
parzelleId = parameters.get("id")
|
parzelleId = parameters.get("id")
|
||||||
|
|
@ -484,10 +814,26 @@ async def executeIntentBasedOperation(
|
||||||
logger.warning(f"Invalid filter fields for Parzelle ignored: {list(invalidFields.keys())}")
|
logger.warning(f"Invalid filter fields for Parzelle ignored: {list(invalidFields.keys())}")
|
||||||
|
|
||||||
parzellen = realEstateInterface.getParzellen(recordFilter=recordFilter if recordFilter else None)
|
parzellen = realEstateInterface.getParzellen(recordFilter=recordFilter if recordFilter else None)
|
||||||
|
|
||||||
|
# Debug logging for empty results
|
||||||
|
if not parzellen and recordFilter:
|
||||||
|
logger.info(f"No Parzellen found matching filter: {recordFilter}")
|
||||||
|
# Get total count to help debug
|
||||||
|
all_parzellen = realEstateInterface.getParzellen(recordFilter=None)
|
||||||
|
logger.info(f"Total Parzellen in database: {len(all_parzellen)}")
|
||||||
|
if all_parzellen:
|
||||||
|
# Show some sample kontextGemeinde values
|
||||||
|
sample_gemeinden = set()
|
||||||
|
for p in all_parzellen[:10]:
|
||||||
|
if p.kontextGemeinde:
|
||||||
|
sample_gemeinden.add(p.kontextGemeinde)
|
||||||
|
logger.info(f"Sample kontextGemeinde values in database: {sample_gemeinden}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"operation": "READ",
|
"operation": "READ",
|
||||||
"entity": "Parzelle",
|
"entity": "Parzelle",
|
||||||
"result": [p.model_dump() for p in parzellen]
|
"result": [p.model_dump() for p in parzellen],
|
||||||
|
"count": len(parzellen)
|
||||||
}
|
}
|
||||||
elif entity == "Gemeinde":
|
elif entity == "Gemeinde":
|
||||||
from modules.datamodels.datamodelRealEstate import Gemeinde
|
from modules.datamodels.datamodelRealEstate import Gemeinde
|
||||||
|
|
@ -507,7 +853,8 @@ async def executeIntentBasedOperation(
|
||||||
return {
|
return {
|
||||||
"operation": "READ",
|
"operation": "READ",
|
||||||
"entity": "Gemeinde",
|
"entity": "Gemeinde",
|
||||||
"result": [g.model_dump() for g in gemeinden]
|
"result": [g.model_dump() for g in gemeinden],
|
||||||
|
"count": len(gemeinden)
|
||||||
}
|
}
|
||||||
elif entity == "Kanton":
|
elif entity == "Kanton":
|
||||||
from modules.datamodels.datamodelRealEstate import Kanton
|
from modules.datamodels.datamodelRealEstate import Kanton
|
||||||
|
|
@ -527,7 +874,8 @@ async def executeIntentBasedOperation(
|
||||||
return {
|
return {
|
||||||
"operation": "READ",
|
"operation": "READ",
|
||||||
"entity": "Kanton",
|
"entity": "Kanton",
|
||||||
"result": [k.model_dump() for k in kantone]
|
"result": [k.model_dump() for k in kantone],
|
||||||
|
"count": len(kantone)
|
||||||
}
|
}
|
||||||
elif entity == "Land":
|
elif entity == "Land":
|
||||||
from modules.datamodels.datamodelRealEstate import Land
|
from modules.datamodels.datamodelRealEstate import Land
|
||||||
|
|
@ -547,7 +895,8 @@ async def executeIntentBasedOperation(
|
||||||
return {
|
return {
|
||||||
"operation": "READ",
|
"operation": "READ",
|
||||||
"entity": "Land",
|
"entity": "Land",
|
||||||
"result": [l.model_dump() for l in laender]
|
"result": [l.model_dump() for l in laender],
|
||||||
|
"count": len(laender)
|
||||||
}
|
}
|
||||||
elif entity == "Dokument":
|
elif entity == "Dokument":
|
||||||
from modules.datamodels.datamodelRealEstate import Dokument
|
from modules.datamodels.datamodelRealEstate import Dokument
|
||||||
|
|
@ -567,7 +916,8 @@ async def executeIntentBasedOperation(
|
||||||
return {
|
return {
|
||||||
"operation": "READ",
|
"operation": "READ",
|
||||||
"entity": "Dokument",
|
"entity": "Dokument",
|
||||||
"result": [d.model_dump() for d in dokumente]
|
"result": [d.model_dump() for d in dokumente],
|
||||||
|
"count": len(dokumente)
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"READ operation not supported for entity: {entity}")
|
raise ValueError(f"READ operation not supported for entity: {entity}")
|
||||||
|
|
|
||||||
|
|
@ -220,12 +220,30 @@ class RealEstateObjects:
|
||||||
|
|
||||||
def getParzellen(self, recordFilter: Optional[Dict[str, Any]] = None) -> List[Parzelle]:
|
def getParzellen(self, recordFilter: Optional[Dict[str, Any]] = None) -> List[Parzelle]:
|
||||||
"""Get all plots matching the filter."""
|
"""Get all plots matching the filter."""
|
||||||
|
original_gemeinde_value = None
|
||||||
|
|
||||||
# Resolve location names to IDs if needed
|
# Resolve location names to IDs if needed
|
||||||
if recordFilter:
|
if recordFilter:
|
||||||
|
# Save original value before resolution for fallback search
|
||||||
|
if "kontextGemeinde" in recordFilter:
|
||||||
|
original_gemeinde_value = recordFilter["kontextGemeinde"]
|
||||||
|
|
||||||
recordFilter = self._resolveLocationFilters(recordFilter)
|
recordFilter = self._resolveLocationFilters(recordFilter)
|
||||||
|
|
||||||
records = self.db.getRecordset(Parzelle, recordFilter=recordFilter or {})
|
records = self.db.getRecordset(Parzelle, recordFilter=recordFilter or {})
|
||||||
|
|
||||||
|
# Fallback: If no records found and we resolved a Gemeinde name,
|
||||||
|
# try searching with the original name for backwards compatibility
|
||||||
|
# (handles case where data has string names instead of UUIDs)
|
||||||
|
if not records and original_gemeinde_value and recordFilter and "kontextGemeinde" in recordFilter:
|
||||||
|
if recordFilter["kontextGemeinde"] != original_gemeinde_value:
|
||||||
|
logger.info(f"No results with resolved UUID, trying with original name '{original_gemeinde_value}'")
|
||||||
|
fallback_filter = recordFilter.copy()
|
||||||
|
fallback_filter["kontextGemeinde"] = original_gemeinde_value
|
||||||
|
records = self.db.getRecordset(Parzelle, recordFilter=fallback_filter)
|
||||||
|
if records:
|
||||||
|
logger.info(f"Found {len(records)} records using original name (legacy data format)")
|
||||||
|
|
||||||
# Apply access control
|
# Apply access control
|
||||||
filtered = self.access.uam(Parzelle, records)
|
filtered = self.access.uam(Parzelle, records)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue