170 lines
5.9 KiB
Python
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
|