160 lines
5.9 KiB
Python
160 lines
5.9 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
"""
|
|
Utility functions for the chatbot module.
|
|
Contains conversation name generation and other utilities.
|
|
"""
|
|
|
|
import logging
|
|
import re
|
|
from typing import Optional
|
|
|
|
from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, OperationTypeEnum, ProcessingModeEnum
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def generate_conversation_name(
|
|
services,
|
|
userPrompt: str,
|
|
userLanguage: str = "en"
|
|
) -> str:
|
|
"""
|
|
Generate a short, descriptive conversation name based on user's prompt.
|
|
|
|
Args:
|
|
services: Services instance with AI access
|
|
userPrompt: The user's input prompt
|
|
userLanguage: User's preferred language (for prompt localization)
|
|
|
|
Returns:
|
|
Short conversation name (max 60 characters)
|
|
"""
|
|
try:
|
|
truncated_prompt = userPrompt[:200] if len(userPrompt) > 200 else userPrompt
|
|
|
|
name_prompt = f"""Create a professional conversation title in THE SAME LANGUAGE as the user's question.
|
|
|
|
Question: "{truncated_prompt}"
|
|
|
|
Rules:
|
|
- Title MUST be in the same language as the question (German→German, French→French, English→English)
|
|
- Max 60 characters, no punctuation (?, !, .)
|
|
- Professional and concise
|
|
- Respond ONLY with the title, nothing else"""
|
|
|
|
await services.ai.ensureAiObjectsInitialized()
|
|
|
|
nameRequest = AiCallRequest(
|
|
prompt=name_prompt,
|
|
options=AiCallOptions(
|
|
resultFormat="txt",
|
|
operationType=OperationTypeEnum.DATA_GENERATE,
|
|
processingMode=ProcessingModeEnum.DETAILED,
|
|
temperature=0.7
|
|
)
|
|
)
|
|
|
|
nameResponse = await services.ai.callAi(nameRequest)
|
|
generated_name = nameResponse.content.strip()
|
|
|
|
# Extract first line and clean up
|
|
generated_name = generated_name.split('\n')[0].strip()
|
|
generated_name = re.sub(r'^(Title|Titel|Titre|Name|Name:):\s*', '', generated_name, flags=re.IGNORECASE)
|
|
generated_name = re.sub(r'^["\']|["\']$', '', generated_name)
|
|
generated_name = re.sub(r'[?!.]+$', '', generated_name) # Remove trailing punctuation
|
|
|
|
# Apply title case
|
|
if generated_name:
|
|
words = generated_name.split()
|
|
capitalized_words = []
|
|
for word in words:
|
|
if word.isupper() and len(word) > 1:
|
|
capitalized_words.append(word) # Keep acronyms
|
|
else:
|
|
capitalized_words.append(word.capitalize())
|
|
generated_name = " ".join(capitalized_words).strip()
|
|
|
|
# Validate and truncate if needed
|
|
if not generated_name or len(generated_name) < 3:
|
|
if userLanguage == "de":
|
|
generated_name = "Chatbot Konversation"
|
|
elif userLanguage == "fr":
|
|
generated_name = "Conversation Chatbot"
|
|
else:
|
|
generated_name = "Chatbot Conversation"
|
|
|
|
if len(generated_name) > 60:
|
|
truncated = generated_name[:57]
|
|
last_space = truncated.rfind(' ')
|
|
generated_name = truncated[:last_space] + "..." if last_space > 30 else truncated + "..."
|
|
|
|
logger.info(f"Generated conversation name: '{generated_name}'")
|
|
return generated_name
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error generating conversation name: {e}", exc_info=True)
|
|
if userLanguage == "de":
|
|
return "Chatbot Konversation"
|
|
elif userLanguage == "fr":
|
|
return "Conversation Chatbot"
|
|
else:
|
|
return "Chatbot Conversation"
|
|
|
|
|
|
def get_empty_results_retry_instructions(empty_count: int) -> str:
|
|
"""
|
|
Get retry instructions when empty results are detected.
|
|
|
|
Args:
|
|
empty_count: Number of queries that returned empty results
|
|
|
|
Returns:
|
|
Formatted instructions string
|
|
"""
|
|
if empty_count == 0:
|
|
return ""
|
|
|
|
return f"""
|
|
⚠️ LEERE ERGEBNISSE ERKANNT ⚠️
|
|
|
|
Es wurden {empty_count} Query(s) ausgeführt, die 0 Zeilen zurückgegeben haben. Versuche alternative Strategien.
|
|
|
|
⚠️ WICHTIG - MAXIMAL 5 QUERIES FÜR PERFORMANCE ⚠️
|
|
|
|
Erstelle MAXIMAL 5 alternative SQL-Queries mit komplett anderen Strategien:
|
|
|
|
1. **Breitere Suche ohne Zertifizierung**: Entferne Zertifizierungsfilter komplett
|
|
- Beispiel: Suche nur nach Netzgerät + einphasig + 10A (ohne UL)
|
|
- Suche in Artikelbezeichnung, Artikelbeschrieb, Keywords
|
|
|
|
2. **Erweiterte Suche nach Netzgeräten mit Ampere-Angaben**: Breitere Ampere-Patterns
|
|
- Beispiel: (Netzteil OR Netzgerät) AND (10A OR 15A OR 20A OR Ampere)
|
|
- Suche auch nach "Ampere" als Begriff, nicht nur Zahlen
|
|
|
|
3. **Breitere UL-Suche bei Netzgeräten**: Suche UL in allen Feldern
|
|
- Beispiel: (UL OR UL-zertifiziert) AND (Netzgerät OR Netzteil OR Power Supply)
|
|
- Suche auch in Keywords-Feld
|
|
|
|
4. **Netzgeräte mit ≥10A ohne weitere Filter**: Minimaler Filter
|
|
- Beispiel: (Netzgerät OR Netzteil) AND (10A OR 15A OR 20A)
|
|
- Keine Filter auf einphasig oder Zertifizierung
|
|
|
|
5. **Zertifizierte Netzgeräte allgemein**: Breite Zertifizierungs-Suche
|
|
- Beispiel: (UL OR CE OR TÜV OR certified OR zertifiziert) AND (Netzgerät OR Netzteil)
|
|
|
|
6. **COUNT-Abfrage für Statistik**: Prüfe ob überhaupt Artikel existieren
|
|
- SELECT COUNT(*) WHERE (Netzgerät OR Netzteil) AND (10A OR 15A OR 20A)
|
|
|
|
7. **Spezifische Suche nach einphasigen Netzgeräten**: Ohne Zertifizierung
|
|
- Beispiel: (einphasig OR 1-phasig OR single phase) AND (Netzgerät OR Netzteil)
|
|
|
|
8. **Fallback mit minimalen Filtern**: Nur Hauptkriterien
|
|
- Beispiel: Netzgerät AND (10A OR 15A OR 20A) - keine weiteren Filter
|
|
|
|
WICHTIG:
|
|
- Erstelle MAXIMAL 5 Queries mit unterschiedlichen Strategien (für Performance)
|
|
- Verwende breitere OR-Bedingungen für alternative Begriffe
|
|
- Entferne zu spezifische Filter, die möglicherweise keine Treffer finden
|
|
- Suche in Artikelbezeichnung, Artikelbeschrieb UND Keywords-Feld
|
|
"""
|