feat:chatbot weiterimplementiert
This commit is contained in:
parent
b6724a797f
commit
6ded28e21a
4 changed files with 667 additions and 888 deletions
|
|
@ -39,15 +39,17 @@ class PreprocessorConnector:
|
|||
|
||||
logger.info("PreprocessorConnector initialized")
|
||||
|
||||
async def executeQuery(self, sql_query: str) -> str:
|
||||
async def executeQuery(self, sql_query: str, return_json: bool = False):
|
||||
"""
|
||||
Execute a SQL query via the preprocessing API.
|
||||
|
||||
Args:
|
||||
sql_query: SQL SELECT query to execute
|
||||
return_json: If True, returns dict with 'text' and 'data' keys. If False, returns formatted string.
|
||||
|
||||
Returns:
|
||||
Formatted result string with query results
|
||||
If return_json=False: Formatted result string with query results
|
||||
If return_json=True: Dict with 'text' (formatted string) and 'data' (raw JSON data list)
|
||||
|
||||
Raises:
|
||||
ValueError: If query is invalid or contains forbidden keywords
|
||||
|
|
@ -57,16 +59,22 @@ class PreprocessorConnector:
|
|||
# Validate query
|
||||
validation_error = self._validateQuery(sql_query)
|
||||
if validation_error:
|
||||
if return_json:
|
||||
return {"text": validation_error, "data": []}
|
||||
return validation_error
|
||||
|
||||
# Check configuration
|
||||
if not self.api_key:
|
||||
error_msg = "Error: PP_QUERY_API_KEY not configured"
|
||||
logger.error(error_msg)
|
||||
if return_json:
|
||||
return {"text": error_msg, "data": []}
|
||||
return error_msg
|
||||
if not self.base_url:
|
||||
error_msg = "Error: PP_QUERY_BASE_URL not configured"
|
||||
logger.error(error_msg)
|
||||
if return_json:
|
||||
return {"text": error_msg, "data": []}
|
||||
return error_msg
|
||||
|
||||
# Make HTTP POST request to preprocessing API
|
||||
|
|
@ -86,7 +94,10 @@ class PreprocessorConnector:
|
|||
# Parse response
|
||||
if not result.get("success"):
|
||||
error_message = result.get("message", "Unknown error")
|
||||
return f"Query failed: {error_message}"
|
||||
error_text = f"Query failed: {error_message}"
|
||||
if return_json:
|
||||
return {"text": error_text, "data": []}
|
||||
return error_text
|
||||
|
||||
# Format results
|
||||
data = result.get("data", [])
|
||||
|
|
@ -97,7 +108,10 @@ class PreprocessorConnector:
|
|||
|
||||
# Format results as string
|
||||
if not display_data:
|
||||
return f"Query executed successfully. Returned {row_count} rows (no data)."
|
||||
result_text = f"Query executed successfully. Returned {row_count} rows (no data)."
|
||||
if return_json:
|
||||
return {"text": result_text, "data": data}
|
||||
return result_text
|
||||
|
||||
# Format each row
|
||||
results = []
|
||||
|
|
@ -110,6 +124,8 @@ class PreprocessorConnector:
|
|||
+ "\n".join(results)
|
||||
)
|
||||
|
||||
if return_json:
|
||||
return {"text": result_text, "data": data}
|
||||
return result_text
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1004,24 +1004,36 @@ class ChatObjects:
|
|||
|
||||
# Create documents in normalized documents table
|
||||
created_documents = []
|
||||
for doc_data in documents_to_create:
|
||||
# Normalize to plain dict before assignment
|
||||
if isinstance(doc_data, ChatDocument):
|
||||
doc_dict = doc_data.model_dump()
|
||||
elif isinstance(doc_data, dict):
|
||||
doc_dict = dict(doc_data)
|
||||
else:
|
||||
# Attempt to coerce to ChatDocument then dump
|
||||
try:
|
||||
doc_dict = ChatDocument(**doc_data).model_dump()
|
||||
except Exception:
|
||||
logger.error("Invalid document data type for message creation")
|
||||
continue
|
||||
|
||||
doc_dict["messageId"] = createdMessage["id"]
|
||||
created_doc = self.createDocument(doc_dict)
|
||||
if created_doc:
|
||||
created_documents.append(created_doc)
|
||||
logger.debug(f"Creating {len(documents_to_create)} document(s) for message {createdMessage['id']}")
|
||||
for idx, doc_data in enumerate(documents_to_create):
|
||||
try:
|
||||
# Normalize to plain dict before assignment
|
||||
if isinstance(doc_data, ChatDocument):
|
||||
doc_dict = doc_data.model_dump()
|
||||
elif isinstance(doc_data, dict):
|
||||
doc_dict = dict(doc_data)
|
||||
else:
|
||||
# Attempt to coerce to ChatDocument then dump
|
||||
try:
|
||||
doc_dict = ChatDocument(**doc_data).model_dump()
|
||||
except Exception as e:
|
||||
logger.error(f"Invalid document data type for message creation (document {idx + 1}/{len(documents_to_create)}): {e}")
|
||||
continue
|
||||
|
||||
# Ensure messageId is set
|
||||
doc_dict["messageId"] = createdMessage["id"]
|
||||
logger.debug(f"Creating document {idx + 1}/{len(documents_to_create)}: fileName={doc_dict.get('fileName', 'unknown')}, fileId={doc_dict.get('fileId', 'unknown')}, messageId={doc_dict.get('messageId', 'unknown')}")
|
||||
|
||||
created_doc = self.createDocument(doc_dict)
|
||||
if created_doc:
|
||||
created_documents.append(created_doc)
|
||||
logger.debug(f"Successfully created document {idx + 1}/{len(documents_to_create)}: {created_doc.fileName} (id: {created_doc.id})")
|
||||
else:
|
||||
logger.error(f"Failed to create document {idx + 1}/{len(documents_to_create)}: createDocument returned None for fileName={doc_dict.get('fileName', 'unknown')}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing document {idx + 1}/{len(documents_to_create)}: {e}", exc_info=True)
|
||||
|
||||
logger.info(f"Created {len(created_documents)}/{len(documents_to_create)} document(s) for message {createdMessage['id']}")
|
||||
|
||||
# Convert to ChatMessage model
|
||||
chat_message = ChatMessage(
|
||||
|
|
@ -1256,12 +1268,18 @@ class ChatObjects:
|
|||
try:
|
||||
# Validate and normalize document data to dict
|
||||
document = ChatDocument(**documentData)
|
||||
logger.debug(f"Creating document in database: fileName={document.fileName}, fileId={document.fileId}, messageId={document.messageId}")
|
||||
created = self.db.recordCreate(ChatDocument, document.model_dump())
|
||||
|
||||
|
||||
return ChatDocument(**created)
|
||||
if created:
|
||||
created_doc = ChatDocument(**created)
|
||||
logger.debug(f"Successfully created document in database: {created_doc.fileName} (id: {created_doc.id})")
|
||||
return created_doc
|
||||
else:
|
||||
logger.error(f"Failed to create document in database: recordCreate returned None for fileName={document.fileName}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating message document: {str(e)}")
|
||||
logger.error(f"Error creating message document: {str(e)}", exc_info=True)
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,18 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult:
|
|||
# Convert to DocumentReferenceList if needed
|
||||
if documentListParam is None:
|
||||
documentList = DocumentReferenceList(references=[])
|
||||
logger.debug(f"ai.process: documentList is None, using empty DocumentReferenceList")
|
||||
elif isinstance(documentListParam, DocumentReferenceList):
|
||||
documentList = documentListParam
|
||||
logger.info(f"ai.process: Received DocumentReferenceList with {len(documentList.references)} references")
|
||||
for idx, ref in enumerate(documentList.references):
|
||||
logger.info(f" Reference {idx + 1}: documentId={ref.documentId}, type={type(ref).__name__}")
|
||||
elif isinstance(documentListParam, str):
|
||||
documentList = DocumentReferenceList.from_string_list([documentListParam])
|
||||
logger.info(f"ai.process: Converted string to DocumentReferenceList with {len(documentList.references)} references")
|
||||
elif isinstance(documentListParam, list):
|
||||
documentList = DocumentReferenceList.from_string_list(documentListParam)
|
||||
logger.info(f"ai.process: Converted list to DocumentReferenceList with {len(documentList.references)} references")
|
||||
else:
|
||||
logger.error(f"Invalid documentList type: {type(documentListParam)}")
|
||||
documentList = DocumentReferenceList(references=[])
|
||||
|
|
@ -152,9 +158,16 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult:
|
|||
)
|
||||
else:
|
||||
# Full mode: use unified callAiContent method
|
||||
# For document generation (xlsx, docx, pdf, etc.), use DATA_GENERATE with document intent
|
||||
from modules.datamodels.datamodelAi import OperationTypeEnum
|
||||
|
||||
# Always use DATA_GENERATE with document intent for ai.process
|
||||
# This ensures proper document generation pipeline is used
|
||||
options = AiCallOptions(
|
||||
resultFormat=output_format
|
||||
resultFormat=output_format,
|
||||
operationType=OperationTypeEnum.DATA_GENERATE
|
||||
)
|
||||
generation_intent = "document"
|
||||
|
||||
# Update progress - calling AI
|
||||
self.services.chat.progressLogUpdate(operationId, 0.6, "Calling AI")
|
||||
|
|
@ -171,17 +184,23 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult:
|
|||
options=options,
|
||||
contentParts=contentParts, # Pre-extracted ContentParts
|
||||
outputFormat=output_format,
|
||||
parentOperationId=operationId
|
||||
parentOperationId=operationId,
|
||||
generationIntent=generation_intent
|
||||
)
|
||||
else:
|
||||
# Pass documentList - callAiContent handles Phases 5A-5E internally
|
||||
# This includes automatic detection of ContentExtracted documents
|
||||
logger.info(f"ai.process: Calling callAiContent with {len(documentList.references)} document references")
|
||||
if documentList.references:
|
||||
for idx, ref in enumerate(documentList.references):
|
||||
logger.info(f" Passing reference {idx + 1}: documentId={ref.documentId}")
|
||||
aiResponse = await self.services.ai.callAiContent(
|
||||
prompt=aiPrompt,
|
||||
options=options,
|
||||
documentList=documentList, # callAiContent macht Phasen 5A-5E
|
||||
outputFormat=output_format,
|
||||
parentOperationId=operationId
|
||||
parentOperationId=operationId,
|
||||
generationIntent=generation_intent
|
||||
)
|
||||
|
||||
# Update progress - processing result
|
||||
|
|
|
|||
Loading…
Reference in a new issue