780 lines
25 KiB
Markdown
780 lines
25 KiB
Markdown
# Schritt 3: Feature-Logik implementieren
|
|
|
|
[← Zurück: Interface erstellen](03-interfaces.md) | [Weiter: Routen erstellen →](05-routes.md)
|
|
|
|
**Datei:** `modules/features/realEstate/mainRealEstate.py`
|
|
|
|
Die Feature-Logik enthält die Geschäftslogik für das Feature. Sie wird von den Routen aufgerufen und arbeitet **stateless** ohne Session-Management.
|
|
|
|
## Übersicht: Stateless Feature-Logik mit AI-Integration
|
|
|
|
Die Feature-Logik verwendet **AI**, um natürliche Sprache direkt in CRUD-Operationen zu übersetzen - ohne Session-Management:
|
|
|
|
```
|
|
User Input (natürliche Sprache)
|
|
↓
|
|
AI-Analyse (Intent-Erkennung)
|
|
↓
|
|
CRUD-Operation identifizieren
|
|
↓
|
|
Parameter extrahieren
|
|
↓
|
|
Interface CRUD-Methode aufrufen
|
|
↓
|
|
Datenbank-Operation ausführen
|
|
↓
|
|
Ergebnis zurückgeben (keine Session-Speicherung)
|
|
```
|
|
|
|
**Beispiel:**
|
|
- User: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
|
- AI analysiert → Intent: CREATE, Entity: Projekt, Parameter: {label: "Hauptstrasse 42"}
|
|
- Feature-Logik ruft auf → `interface.createProjekt(Projekt(label="Hauptstrasse 42"))`
|
|
- Ergebnis wird direkt zurückgegeben (keine Session, keine History)
|
|
|
|
## AI-Integration: Services initialisieren
|
|
|
|
Um AI zu verwenden, müssen Sie die **Services** initialisieren. Services sind eine zentrale Schnittstelle zu verschiedenen Systemkomponenten (AI, Chat, Database, etc.).
|
|
|
|
### Services-Initialisierung
|
|
|
|
```python
|
|
from modules.services import getInterface as getServices
|
|
|
|
# Services für einen User erhalten
|
|
services = getServices(currentUser, workflow=None)
|
|
|
|
# AI-Service verfügbar über:
|
|
aiService = services.ai # Für AI-Aufrufe
|
|
```
|
|
|
|
**Wichtig:** Services werden normalerweise im Feature-Logik-Modul initialisiert und an Funktionen weitergegeben.
|
|
|
|
---
|
|
|
|
## AI-basierte Intent-Erkennung und CRUD-Operationen
|
|
|
|
### Schritt 1: Intent-Analyse mit AI
|
|
|
|
Die AI analysiert User-Input und identifiziert:
|
|
- **Intent**: CREATE, READ, UPDATE, DELETE, QUERY
|
|
- **Entity**: Projekt, Parzelle, Dokument, etc.
|
|
- **Parameter**: Extrahierte Werte aus dem User-Input
|
|
|
|
### Schritt 2: CRUD-Operation ausführen
|
|
|
|
Basierend auf der AI-Analyse wird die entsprechende Interface-Methode aufgerufen.
|
|
|
|
---
|
|
|
|
## Beispiel-Implementierung:
|
|
|
|
```python
|
|
"""
|
|
Real Estate feature main logic.
|
|
Handles chat interface for database queries with AI-powered natural language processing.
|
|
"""
|
|
|
|
import logging
|
|
import json
|
|
from typing import Optional, Dict, Any, List
|
|
from modules.datamodels.datamodelUam import User
|
|
from modules.datamodels.datamodelRealEstate import (
|
|
Projekt,
|
|
Parzelle,
|
|
StatusProzess,
|
|
)
|
|
from modules.interfaces.interfaceDbRealEstateChatObjects import getInterface as getChatInterface
|
|
from modules.interfaces.interfaceDbRealEstateObjects import getInterface as getRealEstateInterface
|
|
from modules.services import getInterface as getServices
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# ===== Direkte Query-Ausführung (stateless) =====
|
|
|
|
async def executeDirectQuery(
|
|
currentUser: User,
|
|
queryText: str,
|
|
parameters: Optional[Dict[str, Any]] = None,
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Execute a database query directly without session management.
|
|
|
|
Args:
|
|
currentUser: Current authenticated user
|
|
queryText: SQL query text
|
|
parameters: Optional parameters for parameterized queries
|
|
|
|
Returns:
|
|
Dictionary containing query result (rows, columns, rowCount)
|
|
|
|
Note:
|
|
- No session or query history is saved
|
|
- Query is executed directly and result is returned
|
|
- For production, validate and sanitize queries before execution
|
|
"""
|
|
try:
|
|
chatInterface = getChatInterface(currentUser)
|
|
|
|
# Execute query directly (no session tracking)
|
|
result = chatInterface.executeQuery(queryText, parameters)
|
|
|
|
logger.info(
|
|
f"Query executed successfully: {result['rowCount']} rows in {result.get('executionTime', 0):.3f}s"
|
|
)
|
|
|
|
return {
|
|
"status": "success",
|
|
"rows": result["rows"],
|
|
"columns": result["columns"],
|
|
"rowCount": result["rowCount"],
|
|
"executionTime": result.get("executionTime", 0),
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error executing query: {str(e)}")
|
|
raise
|
|
|
|
|
|
# ===== AI-basierte Intent-Erkennung und CRUD-Operationen =====
|
|
|
|
async def processNaturalLanguageCommand(
|
|
currentUser: User,
|
|
userInput: str,
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Process natural language user input and execute corresponding CRUD operations.
|
|
|
|
Uses AI to analyze user intent and extract parameters, then executes the appropriate
|
|
CRUD operation through the interface. Works stateless without session management.
|
|
|
|
Args:
|
|
currentUser: Current authenticated user
|
|
userInput: Natural language command from user
|
|
|
|
Returns:
|
|
Dictionary containing operation result and metadata
|
|
|
|
Example user inputs:
|
|
- "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
|
- "Zeige mir alle Projekte in Zürich"
|
|
- "Aktualisiere Projekt XYZ mit Status 'Planung'"
|
|
- "Lösche Parzelle ABC"
|
|
- "SELECT * FROM Projekt WHERE plz = '8000'"
|
|
"""
|
|
try:
|
|
# Initialize services for AI access
|
|
services = getServices(currentUser, workflow=None)
|
|
aiService = services.ai
|
|
|
|
# Step 1: Analyze user intent with AI
|
|
intentAnalysis = await analyzeUserIntent(aiService, userInput)
|
|
|
|
logger.info(f"Intent analysis result: {intentAnalysis}")
|
|
|
|
# Step 2: Execute CRUD operation based on intent
|
|
result = await executeIntentBasedOperation(
|
|
currentUser=currentUser,
|
|
intent=intentAnalysis["intent"],
|
|
entity=intentAnalysis["entity"],
|
|
parameters=intentAnalysis["parameters"],
|
|
)
|
|
|
|
return {
|
|
"success": True,
|
|
"intent": intentAnalysis["intent"],
|
|
"entity": intentAnalysis["entity"],
|
|
"result": result,
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error processing natural language command: {str(e)}")
|
|
raise
|
|
|
|
|
|
async def analyzeUserIntent(
|
|
aiService,
|
|
userInput: str
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Use AI to analyze user input and extract intent, entity, and parameters.
|
|
|
|
Args:
|
|
aiService: AI service instance
|
|
userInput: Natural language user input
|
|
|
|
Returns:
|
|
Dictionary with 'intent', 'entity', and 'parameters'
|
|
"""
|
|
# Create a structured prompt for intent analysis
|
|
intentPrompt = f"""
|
|
Analyze the following user command and extract the intent, entity, and parameters.
|
|
|
|
User Command: "{userInput}"
|
|
|
|
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
|
|
|
|
Available entities:
|
|
- Projekt: Real estate project
|
|
- Parzelle: Plot/parcel
|
|
- Dokument: Document
|
|
- Kanton: Canton
|
|
- Gemeinde: Municipality
|
|
|
|
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
|
|
// For READ: include filter criteria
|
|
// For DELETE: include entity ID if mentioned
|
|
// For QUERY: include query text or natural language query
|
|
}},
|
|
"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: "SELECT * FROM Projekt WHERE plz = '8000'"
|
|
Output: {{"intent": "QUERY", "entity": null, "parameters": {{"queryText": "SELECT * FROM Projekt WHERE plz = '8000'", "queryType": "sql"}}, "confidence": 1.0}}
|
|
"""
|
|
|
|
try:
|
|
# Use AI planning call for structured JSON response
|
|
response = await aiService.callAiPlanning(
|
|
prompt=intentPrompt,
|
|
debugType="intentanalysis"
|
|
)
|
|
|
|
# Parse JSON response
|
|
intentData = json.loads(response)
|
|
|
|
# Validate response structure
|
|
if "intent" not in intentData or "entity" not in intentData:
|
|
raise ValueError("Invalid intent analysis response structure")
|
|
|
|
return intentData
|
|
|
|
except json.JSONDecodeError as e:
|
|
logger.error(f"Failed to parse AI intent analysis response: {e}")
|
|
logger.error(f"Raw response: {response}")
|
|
raise ValueError(f"AI returned invalid JSON: {str(e)}")
|
|
except Exception as e:
|
|
logger.error(f"Error analyzing user intent: {str(e)}")
|
|
raise
|
|
|
|
|
|
async def executeIntentBasedOperation(
|
|
currentUser: User,
|
|
intent: str,
|
|
entity: Optional[str],
|
|
parameters: Dict[str, Any],
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Execute CRUD operation based on analyzed intent.
|
|
|
|
Args:
|
|
currentUser: Current authenticated user
|
|
intent: Intent from AI analysis (CREATE, READ, UPDATE, DELETE, QUERY)
|
|
entity: Entity type from AI analysis
|
|
parameters: Extracted parameters from AI analysis
|
|
|
|
Returns:
|
|
Operation result
|
|
"""
|
|
try:
|
|
if intent == "QUERY":
|
|
# Execute database query directly (stateless)
|
|
queryText = parameters.get("queryText", "")
|
|
|
|
result = await executeDirectQuery(
|
|
currentUser=currentUser,
|
|
queryText=queryText,
|
|
parameters=parameters.get("queryParameters"),
|
|
)
|
|
return result
|
|
|
|
elif intent == "CREATE":
|
|
# Create new entity
|
|
realEstateInterface = getRealEstateInterface(currentUser)
|
|
|
|
if entity == "Projekt":
|
|
projekt = Projekt(
|
|
mandateId=currentUser.mandateId,
|
|
label=parameters.get("label", ""),
|
|
statusProzess=StatusProzess(parameters.get("statusProzess", "EINGANG")) if parameters.get("statusProzess") else None,
|
|
)
|
|
created = realEstateInterface.createProjekt(projekt)
|
|
return {"operation": "CREATE", "entity": "Projekt", "result": created.model_dump()}
|
|
|
|
elif entity == "Parzelle":
|
|
parzelle = Parzelle(
|
|
mandateId=currentUser.mandateId,
|
|
label=parameters.get("label", ""),
|
|
# ... weitere Parameter
|
|
)
|
|
created = realEstateInterface.createParzelle(parzelle)
|
|
return {"operation": "CREATE", "entity": "Parzelle", "result": created.model_dump()}
|
|
|
|
else:
|
|
raise ValueError(f"CREATE operation not supported for entity: {entity}")
|
|
|
|
elif intent == "READ":
|
|
# Read entities
|
|
realEstateInterface = getRealEstateInterface(currentUser)
|
|
|
|
if entity == "Projekt":
|
|
# Apply filters from parameters
|
|
projektId = parameters.get("id")
|
|
if projektId:
|
|
projekt = realEstateInterface.getProjekt(projektId)
|
|
return {"operation": "READ", "entity": "Projekt", "result": projekt.model_dump() if projekt else None}
|
|
else:
|
|
# List all projects (with optional filters)
|
|
# Note: You may need to implement getProjekte() method
|
|
raise NotImplementedError("List operation needs to be implemented")
|
|
|
|
else:
|
|
raise ValueError(f"READ operation not supported for entity: {entity}")
|
|
|
|
elif intent == "UPDATE":
|
|
# Update existing entity
|
|
realEstateInterface = getRealEstateInterface(currentUser)
|
|
|
|
if entity == "Projekt":
|
|
projektId = parameters.get("id")
|
|
if not projektId:
|
|
raise ValueError("UPDATE operation requires entity ID")
|
|
|
|
# Get existing projekt
|
|
projekt = realEstateInterface.getProjekt(projektId)
|
|
if not projekt:
|
|
raise ValueError(f"Projekt {projektId} not found")
|
|
|
|
# Update fields
|
|
updateData = {k: v for k, v in parameters.items() if k != "id"}
|
|
updated = realEstateInterface.updateProjekt(projektId, updateData)
|
|
return {"operation": "UPDATE", "entity": "Projekt", "result": updated.model_dump()}
|
|
|
|
else:
|
|
raise ValueError(f"UPDATE operation not supported for entity: {entity}")
|
|
|
|
elif intent == "DELETE":
|
|
# Delete entity
|
|
realEstateInterface = getRealEstateInterface(currentUser)
|
|
|
|
if entity == "Projekt":
|
|
projektId = parameters.get("id")
|
|
if not projektId:
|
|
raise ValueError("DELETE operation requires entity ID")
|
|
|
|
success = realEstateInterface.deleteProjekt(projektId)
|
|
return {"operation": "DELETE", "entity": "Projekt", "success": success}
|
|
|
|
else:
|
|
raise ValueError(f"DELETE operation not supported for entity: {entity}")
|
|
|
|
else:
|
|
raise ValueError(f"Unknown intent: {intent}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error executing intent-based operation: {str(e)}")
|
|
raise
|
|
|
|
|
|
# ===== Erweiterte Query-Funktion mit AI-Unterstützung =====
|
|
|
|
async def executeNaturalLanguageQuery(
|
|
currentUser: User,
|
|
naturalLanguageQuery: str,
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Execute a natural language query by translating it to SQL using AI.
|
|
|
|
Args:
|
|
currentUser: Current authenticated user
|
|
naturalLanguageQuery: Natural language query (e.g., "Zeige mir alle Projekte in Zürich")
|
|
|
|
Returns:
|
|
Query result with metadata (stateless, no session)
|
|
"""
|
|
try:
|
|
services = getServices(currentUser, workflow=None)
|
|
aiService = services.ai
|
|
|
|
# Step 1: Translate natural language to SQL using AI
|
|
sqlQuery = await translateNaturalLanguageToSQL(aiService, naturalLanguageQuery, currentUser.mandateId)
|
|
|
|
logger.info(f"Translated '{naturalLanguageQuery}' to SQL: {sqlQuery}")
|
|
|
|
# Step 2: Execute the SQL query directly (stateless)
|
|
result = await executeDirectQuery(
|
|
currentUser=currentUser,
|
|
queryText=sqlQuery,
|
|
)
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error executing natural language query: {str(e)}")
|
|
raise
|
|
|
|
|
|
async def translateNaturalLanguageToSQL(
|
|
aiService,
|
|
naturalLanguageQuery: str,
|
|
mandateId: str
|
|
) -> str:
|
|
"""
|
|
Use AI to translate natural language query to SQL.
|
|
|
|
Args:
|
|
aiService: AI service instance
|
|
naturalLanguageQuery: Natural language query
|
|
mandateId: User's mandate ID for filtering
|
|
|
|
Returns:
|
|
SQL query string with mandateId filter applied
|
|
"""
|
|
translationPrompt = f"""
|
|
Translate the following natural language query into a valid PostgreSQL SQL SELECT statement.
|
|
|
|
Natural Language Query: "{naturalLanguageQuery}"
|
|
|
|
Available tables and their fields:
|
|
- Projekt: id, mandateId, label, statusProzess, perimeter, baulinie, parzellen (JSONB), dokumente (JSONB)
|
|
- Parzelle: id, mandateId, label, strasseNr, plz, bauzone, az, bz, kontextKanton, kontextGemeinde
|
|
- Dokument: id, mandateId, label, dokumentTyp, dokumentReferenz, mimeType
|
|
- Kanton: id, mandateId, label, abk
|
|
- Gemeinde: id, mandateId, label, plz
|
|
|
|
Rules:
|
|
1. Always include 'mandateId' filter based on user context (use placeholder {{mandateId}})
|
|
2. Only use SELECT statements (no INSERT, UPDATE, DELETE)
|
|
3. Return ONLY the SQL query, no explanations
|
|
4. Use proper PostgreSQL syntax
|
|
5. For text searches, use ILIKE for case-insensitive matching
|
|
|
|
Examples:
|
|
- Input: "Zeige mir alle Projekte"
|
|
Output: SELECT * FROM Projekt WHERE mandateId = '{{mandateId}}'
|
|
|
|
- Input: "Zeige mir alle Parzellen in Zürich"
|
|
Output: SELECT p.* FROM Parzelle p JOIN Gemeinde g ON p.kontextGemeinde = g.id WHERE g.label ILIKE '%Zürich%' AND p.mandateId = '{{mandateId}}'
|
|
|
|
- Input: "Wie viele Projekte haben Status 'Planung'?"
|
|
Output: SELECT COUNT(*) as count FROM Projekt WHERE statusProzess = 'Planung' AND mandateId = '{{mandateId}}'
|
|
|
|
Now translate this query:
|
|
"""
|
|
|
|
try:
|
|
# Use AI planning call for SQL generation
|
|
response = await aiService.callAiPlanning(
|
|
prompt=translationPrompt,
|
|
debugType="sqltranslation"
|
|
)
|
|
|
|
# Clean response (remove markdown code blocks if present)
|
|
sqlQuery = response.strip()
|
|
if sqlQuery.startswith("```sql"):
|
|
sqlQuery = sqlQuery[6:]
|
|
if sqlQuery.startswith("```"):
|
|
sqlQuery = sqlQuery[3:]
|
|
if sqlQuery.endswith("```"):
|
|
sqlQuery = sqlQuery[:-3]
|
|
sqlQuery = sqlQuery.strip()
|
|
|
|
# Replace placeholder with actual mandateId
|
|
sqlQuery = sqlQuery.replace("{{mandateId}}", mandateId)
|
|
|
|
return sqlQuery
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error translating natural language to SQL: {str(e)}")
|
|
raise ValueError(f"Failed to translate query: {str(e)}")
|
|
```
|
|
|
|
## Wichtige Punkte:
|
|
|
|
### 1. Services-Initialisierung
|
|
|
|
- **`getServices(currentUser, workflow=None)`** - Initialisiert Services für AI-Zugriff
|
|
- **`services.ai`** - Zugriff auf AI-Service für AI-Aufrufe
|
|
|
|
### 2. AI-Aufrufe
|
|
|
|
- **`callAiPlanning()`** - Für strukturierte JSON-Antworten (Intent-Analyse, SQL-Übersetzung)
|
|
- **`callAiText()`** - Für einfache Text-Generierung
|
|
- **`callAiDocuments()`** - Für Dokumenten-Verarbeitung
|
|
|
|
### 3. Intent-Analyse
|
|
|
|
Die AI analysiert User-Input und gibt zurück:
|
|
- **Intent**: CREATE, READ, UPDATE, DELETE, QUERY
|
|
- **Entity**: Projekt, Parzelle, Dokument, etc.
|
|
- **Parameters**: Extrahierte Werte aus dem Input
|
|
|
|
### 4. CRUD-Operationen
|
|
|
|
Basierend auf der Intent-Analyse:
|
|
- **CREATE** → `interface.createProjekt()`, `interface.createParzelle()`, etc.
|
|
- **READ** → `interface.getProjekt()`, `interface.getParzelle()`, etc.
|
|
- **UPDATE** → `interface.updateProjekt()`, etc.
|
|
- **DELETE** → `interface.deleteProjekt()`, etc.
|
|
- **QUERY** → `interface.executeQuery()` oder `executeDatabaseQuery()`
|
|
|
|
### 5. Natural Language to SQL
|
|
|
|
- AI übersetzt natürliche Sprache in SQL-Queries
|
|
- Automatische Validierung und Sanitization empfohlen
|
|
- MandateId-Filter wird automatisch hinzugefügt
|
|
|
|
### 6. Error Handling
|
|
|
|
- Umfassendes Error Handling für AI-Aufrufe
|
|
- JSON-Parsing mit Fallback
|
|
- Logging für Debugging
|
|
|
|
---
|
|
|
|
## Beispiel-Verwendung:
|
|
|
|
```python
|
|
# In einer Route (stateless):
|
|
@router.post("/command")
|
|
async def process_command(
|
|
userInput: str = Body(...),
|
|
currentUser: User = Depends(getCurrentUser)
|
|
):
|
|
result = await processNaturalLanguageCommand(
|
|
currentUser=currentUser,
|
|
userInput=userInput
|
|
)
|
|
return result
|
|
|
|
# Direkte Query (stateless):
|
|
@router.post("/query")
|
|
async def execute_query(
|
|
queryText: str = Body(...),
|
|
currentUser: User = Depends(getCurrentUser)
|
|
):
|
|
result = await executeDirectQuery(
|
|
currentUser=currentUser,
|
|
queryText=queryText
|
|
)
|
|
return result
|
|
```
|
|
|
|
**User-Input-Beispiele:**
|
|
- `"Erstelle ein neues Projekt namens 'Hauptstrasse 42'"`
|
|
- `"Zeige mir alle Projekte in Zürich"`
|
|
- `"Aktualisiere Projekt XYZ mit Status 'Planung'"`
|
|
- `"Wie viele Parzellen haben Bauzone W3?"`
|
|
|
|
---
|
|
|
|
## Vollständiger Flow: User-Input → CRUD-Operation (stateless)
|
|
|
|
### Beispiel: "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"
|
|
|
|
```
|
|
1. User sendet HTTP POST Request
|
|
POST /api/realestate/command
|
|
Body: {"userInput": "Erstelle ein neues Projekt namens 'Hauptstrasse 42'"}
|
|
|
|
2. Route ruft Feature-Logik auf
|
|
→ processNaturalLanguageCommand(currentUser, userInput)
|
|
# Keine Session-ID notwendig!
|
|
|
|
3. Feature-Logik initialisiert Services
|
|
→ services = getServices(currentUser, workflow=None)
|
|
→ aiService = services.ai
|
|
|
|
4. AI analysiert User-Input
|
|
→ analyzeUserIntent(aiService, userInput)
|
|
→ AI gibt zurück:
|
|
{
|
|
"intent": "CREATE",
|
|
"entity": "Projekt",
|
|
"parameters": {"label": "Hauptstrasse 42"},
|
|
"confidence": 0.95
|
|
}
|
|
|
|
5. Feature-Logik führt CRUD-Operation aus
|
|
→ executeIntentBasedOperation(intent="CREATE", entity="Projekt", ...)
|
|
→ realEstateInterface = getRealEstateInterface(currentUser)
|
|
→ projekt = Projekt(mandateId=..., label="Hauptstrasse 42")
|
|
→ created = realEstateInterface.createProjekt(projekt)
|
|
|
|
6. Interface speichert in Datenbank
|
|
→ DatabaseConnector.recordCreate(Projekt, projekt.model_dump())
|
|
→ PostgreSQL INSERT INTO Projekt ...
|
|
|
|
7. Ergebnis wird direkt zurückgegeben
|
|
→ Route gibt HTTP Response zurück
|
|
→ Keine Session-Speicherung, keine History
|
|
→ Frontend zeigt Erfolg
|
|
```
|
|
|
|
---
|
|
|
|
## AI-Service Methoden im Detail
|
|
|
|
### `callAiPlanning()` - Für strukturierte Antworten
|
|
|
|
**Verwendung:** Intent-Analyse, SQL-Übersetzung, strukturierte Daten-Extraktion
|
|
|
|
```python
|
|
response = await aiService.callAiPlanning(
|
|
prompt=intentPrompt,
|
|
debugType="intentanalysis" # Optional: für Debug-Dateien
|
|
)
|
|
# Response ist JSON-String, muss geparst werden
|
|
intentData = json.loads(response)
|
|
```
|
|
|
|
**Vorteile:**
|
|
- Optimiert für strukturierte JSON-Antworten
|
|
- Verwendet beste Modelle für Planungs-Aufgaben
|
|
- Automatisches Debug-File-Writing
|
|
|
|
### `callAiText()` - Für einfache Text-Generierung
|
|
|
|
**Verwendung:** Text-Generierung, Zusammenfassungen, Erklärungen
|
|
|
|
```python
|
|
response = await aiService.callAiText(
|
|
prompt="Erkläre mir...",
|
|
documents=None, # Optional: Dokumente für Kontext
|
|
options=AiCallOptions(...)
|
|
)
|
|
# Response ist direkt Text-String
|
|
```
|
|
|
|
### `callAiDocuments()` - Für Dokumenten-Verarbeitung
|
|
|
|
**Verwendung:** Dokumenten-Analyse, Extraktion, Generierung mit Dokumenten-Kontext
|
|
|
|
```python
|
|
response = await aiService.callAiDocuments(
|
|
prompt="Analysiere diese Dokumente...",
|
|
documents=[ChatDocument(...), ...],
|
|
options=AiCallOptions(...),
|
|
outputFormat="json" # Optional: Format für Output
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices für AI-Integration
|
|
|
|
### 1. Prompt-Engineering
|
|
|
|
- **Klare Struktur**: Definieren Sie genau, welche Antwort Sie erwarten
|
|
- **Beispiele**: Geben Sie Beispiele für bessere Ergebnisse
|
|
- **Format**: Spezifizieren Sie das erwartete Format (JSON, SQL, etc.)
|
|
|
|
### 2. Error Handling
|
|
|
|
- **JSON-Parsing**: Immer try/except für JSON-Parsing
|
|
- **Fallback**: Planen Sie Fallback-Strategien bei AI-Fehlern
|
|
- **Validierung**: Validieren Sie AI-Antworten vor Verwendung
|
|
|
|
### 3. Sicherheit
|
|
|
|
- **Query-Validierung**: Validieren Sie SQL-Queries vor Ausführung
|
|
- **Parameter-Sanitization**: Sanitizen Sie alle Parameter
|
|
- **MandateId-Filter**: Stellen Sie sicher, dass MandateId immer gefiltert wird
|
|
|
|
### 4. Performance
|
|
|
|
- **Caching**: Cache häufige AI-Antworten wenn möglich
|
|
- **Model-Auswahl**: Lassen Sie das System automatisch das beste Modell wählen
|
|
- **Async**: Nutzen Sie async/await für nicht-blockierende Operationen
|
|
|
|
### 5. Debugging
|
|
|
|
- **Debug-Files**: Nutzen Sie `debugType` Parameter für Debug-Dateien
|
|
- **Logging**: Loggen Sie alle AI-Aufrufe und Antworten
|
|
- **Confidence-Scores**: Nutzen Sie Confidence-Scores für Fehlerbehandlung
|
|
|
|
---
|
|
|
|
## Erweiterte Features
|
|
|
|
### Schema-Aware Prompting
|
|
|
|
Sie können das Datenbank-Schema in Prompts einbinden:
|
|
|
|
```python
|
|
# Lade Schema-Informationen
|
|
schemaInfo = getDatabaseSchema() # Ihre Funktion
|
|
|
|
prompt = f"""
|
|
Available database schema:
|
|
{schemaInfo}
|
|
|
|
User query: "{userInput}"
|
|
...
|
|
"""
|
|
```
|
|
|
|
### Context-Aware Operations (Optional)
|
|
|
|
Falls Sie später Kontext zwischen Queries benötigen, können Sie optional eine Session verwenden:
|
|
|
|
```python
|
|
# Optional: Session für Kontext (nur wenn nötig)
|
|
# Für stateless Operationen nicht notwendig
|
|
|
|
# Falls Session gewünscht:
|
|
sessionId = parameters.get("sessionId") # Optional
|
|
if sessionId:
|
|
previousQueries = interface.getQueries(sessionId=sessionId)
|
|
context = "\n".join([q.queryText for q in previousQueries[-5:]])
|
|
else:
|
|
context = "" # Kein Kontext bei stateless Operationen
|
|
|
|
prompt = f"""
|
|
{context if context else ""}
|
|
User query: "{userInput}"
|
|
...
|
|
"""
|
|
```
|
|
|
|
### Multi-Step Operations
|
|
|
|
Für komplexe Operationen können Sie mehrere AI-Calls machen:
|
|
|
|
```python
|
|
# Schritt 1: Intent-Analyse
|
|
intent = await analyzeUserIntent(aiService, userInput)
|
|
|
|
# Schritt 2: Parameter-Validierung
|
|
if intent["intent"] == "CREATE":
|
|
validatedParams = await validateParameters(aiService, intent["parameters"])
|
|
|
|
# Schritt 3: CRUD-Operation
|
|
result = await executeIntentBasedOperation(...)
|
|
```
|
|
|
|
---
|
|
|
|
[← Zurück: Interface erstellen](03-interfaces.md) | [Weiter: Routen erstellen →](05-routes.md)
|
|
|
|
|
|
|