gateway/modules/features/chatbot/chatbotConstants.py

170 lines
5.9 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Chatbot constants and helper functions.
"""
import logging
from typing import Optional
from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, OperationTypeEnum, PriorityEnum, ProcessingModeEnum
logger = logging.getLogger(__name__)
async def generate_conversation_name(
services,
prompt: str,
user_language: Optional[str] = None
) -> str:
"""
Generate a conversation name from the user's prompt using AI.
Creates a concise, informative summary name in German based on the user input.
Args:
services: Services object with AI service
prompt: User's input prompt (always in German)
user_language: User's language preference (not used, always German)
Returns:
A short, informative conversation name in German
"""
if not prompt or not prompt.strip():
return "Neue Unterhaltung"
try:
# Check if AI service is available
if not hasattr(services, 'ai') or services.ai is None:
logger.warning("AI service not available, generating name from prompt")
return generate_name_from_prompt(prompt)
# Ensure AI service is initialized before use
await services.ai.ensureAiObjectsInitialized()
# Create AI prompt - very explicit that answer must be in German
ai_prompt = f"""Du bist ein deutscher Assistent. Der Benutzer hat folgende Anfrage auf Deutsch gestellt:
"{prompt.strip()}"
Erstelle einen kurzen, zusammenfassenden Titel für diese Unterhaltung. Der Titel muss:
- Auf Deutsch sein (KEIN Englisch!)
- Maximal 50 Zeichen lang sein
- Das Hauptthema zusammenfassen
- Informativ sein
Beispiele für gute deutsche Titel:
- "LED-Artikel Suche"
- "Lagerbestandsabfrage"
- "Produktinformationen"
- "Artikel-Suche"
Antworte NUR mit dem deutschen Titel, ohne Anführungszeichen oder Erklärungen."""
# Create AI request
request = AiCallRequest(
prompt=ai_prompt,
context="",
options=AiCallOptions(
operationType=OperationTypeEnum.DATA_GENERATE,
priority=PriorityEnum.SPEED,
processingMode=ProcessingModeEnum.BASIC,
compressPrompt=False,
compressContext=False,
temperature=0.3 # Lower temperature for more consistent German output
)
)
# Call AI service
logger.info(f"Calling AI to generate conversation name for prompt: {prompt[:50]}...")
response = await services.ai.callAi(request)
if not response or not hasattr(response, 'content') or not response.content:
logger.warning("AI response invalid, generating name from prompt")
return generate_name_from_prompt(prompt)
logger.info(f"AI response received: {response.content[:100]}...")
# Clean up the AI response
name = str(response.content).strip()
name = name.strip('"\'')
# Remove markdown code blocks if present
if name.startswith('```'):
lines = name.split('\n')
if len(lines) > 1:
name = '\n'.join(lines[1:-1]) if lines[-1].strip() == '```' else '\n'.join(lines[1:])
# Remove newlines and extra spaces
name = " ".join(name.split())
# Check if name contains English words - if so, generate from prompt instead
name_lower = name.lower()
english_words = ["search", "find", "show", "display", "query", "article", "product", "item", "led articles", "product search"]
if any(word in name_lower for word in english_words):
logger.warning(f"AI generated English name '{name}', generating from prompt instead")
return generate_name_from_prompt(prompt)
# Limit to 50 characters
if len(name) > 50:
name = name[:47] + "..."
# If we got a valid name, return it
if name and len(name) >= 3:
logger.info(f"Successfully generated conversation name via AI: '{name}'")
return name
else:
logger.warning(f"Generated name is too short: '{name}', generating from prompt")
return generate_name_from_prompt(prompt)
except Exception as e:
logger.error(f"Error generating conversation name with AI: {e}", exc_info=True)
return generate_name_from_prompt(prompt)
def generate_name_from_prompt(prompt: str) -> str:
"""
Generate a conversation name directly from the German prompt.
Creates a concise title by extracting key words and formatting them.
Args:
prompt: User's input prompt in German
Returns:
A short conversation name in German
"""
if not prompt or not prompt.strip():
return "Neue Unterhaltung"
# Clean up the prompt
name = prompt.strip()
# Remove newlines and extra spaces
name = " ".join(name.split())
# Remove common question words and phrases
question_words = ["wie", "was", "wo", "wann", "wer", "welche", "welcher", "welches"]
words = name.split()
filtered_words = [w for w in words if w.lower() not in question_words]
if filtered_words:
name = " ".join(filtered_words)
# Capitalize first letter
if name:
name = name[0].upper() + name[1:] if len(name) > 1 else name.upper()
# Limit to 50 characters
if len(name) > 50:
# Try to cut at word boundary
truncated = name[:47]
last_space = truncated.rfind(' ')
if last_space > 20: # Only cut at word boundary if reasonable
name = truncated[:last_space] + "..."
else:
name = truncated + "..."
# If name is empty or too short, use default
if not name or len(name) < 3:
return "Neue Unterhaltung"
return name