diff --git a/modules/features/commcoach/serviceCommcoach.py b/modules/features/commcoach/serviceCommcoach.py
index 24c23044..8151d343 100644
--- a/modules/features/commcoach/serviceCommcoach.py
+++ b/modules/features/commcoach/serviceCommcoach.py
@@ -86,6 +86,27 @@ def cleanupSessionEvents(sessionId: str):
CHUNK_WORD_SIZE = 4
CHUNK_DELAY_SECONDS = 0.05
+def _wrapEmailHtml(contentHtml: str) -> str:
+ """Wrap AI-generated HTML content in a styled email shell."""
+ return f"""
+
+
+
+
+
+
+
Coaching-Session Zusammenfassung
+
PowerOn CommCoach
+
+
{contentHtml}
+
+
Diese Zusammenfassung wurde automatisch erstellt.
+
+
+
+
+"""
+
DOC_INTENT_MAX_DOCS = 3
DOC_CONTENT_MAX_CHARS = 3000
@@ -634,14 +655,21 @@ class CommcoachService:
})
return session
- # Generate summary
+ # Generate summary (AI returns JSON with summary + emailHtml)
+ summary = None
+ emailHtml = None
try:
summaryPrompt = aiPrompts.buildSummaryPrompt(messages, context.get("title", "Coaching"))
- summaryResponse = await self._callAi("Du bist ein präziser Zusammenfasser.", summaryPrompt)
- summary = summaryResponse.content.strip() if summaryResponse and summaryResponse.errorCount == 0 else None
+ summaryResponse = await self._callAi("Du bist ein präziser Zusammenfasser. Antworte NUR als JSON.", summaryPrompt)
+ if summaryResponse and summaryResponse.errorCount == 0 and summaryResponse.content:
+ parsed = aiPrompts.parseJsonResponse(summaryResponse.content.strip(), None)
+ if isinstance(parsed, dict):
+ summary = parsed.get("summary") or parsed.get("text")
+ emailHtml = parsed.get("emailHtml")
+ else:
+ summary = summaryResponse.content.strip()
except Exception as e:
logger.warning(f"Summary generation failed: {e}")
- summary = None
keyTopics = None
if summary:
@@ -782,7 +810,8 @@ class CommcoachService:
# Send email summary
if summary:
- await self._sendSessionEmail(session, summary, interface)
+ contextTitle = context.get("title", "Coaching") if context else "Coaching"
+ await self._sendSessionEmail(session, summary, emailHtml, contextTitle, interface)
await emitSessionEvent(sessionId, "sessionState", {
"status": "completed",
@@ -833,8 +862,8 @@ class CommcoachService:
except Exception as e:
logger.warning(f"Failed to update streak: {e}")
- async def _sendSessionEmail(self, session: Dict[str, Any], summary: str, interface):
- """Send session summary via email if enabled."""
+ async def _sendSessionEmail(self, session: Dict[str, Any], summary: str, emailHtml: str, contextTitle: str, interface):
+ """Send session summary via email if enabled. Uses AI-generated HTML directly."""
try:
profile = interface.getProfile(self.userId, self.instanceId)
if profile and not profile.get("emailSummaryEnabled", True):
@@ -849,13 +878,10 @@ class CommcoachService:
return
messaging = getMessagingInterface()
- subject = f"Coaching-Session Zusammenfassung: {session.get('contextId', 'Session')}"
- htmlMessage = f"""
- Coaching-Session Zusammenfassung
- {summary.replace(chr(10), '
')}
-
- Diese Zusammenfassung wurde automatisch erstellt.
- """
+ subject = f"Coaching-Session Zusammenfassung: {contextTitle}"
+
+ contentHtml = emailHtml if emailHtml else f"{summary}
"
+ htmlMessage = _wrapEmailHtml(contentHtml)
messaging.send("email", user.email, subject, htmlMessage)
interface.updateSession(session.get("id"), {"emailSent": True})
diff --git a/modules/features/commcoach/serviceCommcoachAi.py b/modules/features/commcoach/serviceCommcoachAi.py
index 11844c28..8db9e61c 100644
--- a/modules/features/commcoach/serviceCommcoachAi.py
+++ b/modules/features/commcoach/serviceCommcoachAi.py
@@ -260,24 +260,35 @@ Fuer ein NEUES Dokument: {"title": "...", "content": "...Inhalt..."}"""
def buildSummaryPrompt(messages: List[Dict[str, Any]], contextTitle: str) -> str:
- """Build a prompt to generate a session summary."""
+ """Build a prompt to generate a session summary as JSON with plain text and styled HTML email."""
conversation = ""
for msg in messages:
role = "Benutzer" if msg.get("role") == "user" else "Coach"
conversation += f"\n{role}: {msg.get('content', '')}"
- return f"""Erstelle eine kompakte Zusammenfassung dieser Coaching-Session zum Thema "{contextTitle}".
+ return f"""Erstelle eine Zusammenfassung dieser Coaching-Session zum Thema "{contextTitle}".
-Struktur:
-1. **Kernthema**: Was wurde besprochen (1-2 Sätze)
-2. **Erkenntnisse**: Was wurde erkannt/gelernt (Stichpunkte)
-3. **Nächste Schritte**: Konkrete Aufgaben für den Benutzer (Stichpunkte)
-4. **Fortschritt**: Einschätzung des Fortschritts
+Antworte AUSSCHLIESSLICH als JSON mit zwei Feldern:
+
+{{
+ "summary": "Kompakte Zusammenfassung als Plaintext (fuer Anzeige in der App). Struktur: 1. Kernthema, 2. Erkenntnisse, 3. Naechste Schritte, 4. Fortschritt.",
+ "emailHtml": "...
"
+}}
+
+Fuer "emailHtml": Erstelle ein professionell formatiertes HTML-Fragment (KEIN vollstaendiges HTML-Dokument, nur der Inhalt-Block).
+Verwende inline CSS fuer schoene Darstellung in E-Mail-Clients:
+- Verwende fuer Abschnitte (color: #1e40af; margin: 20px 0 8px; font-size: 16px)
+- Verwende /- fuer Stichpunkte (margin: 4px 0; line-height: 1.6)
+- Verwende fuer Hervorhebungen
+- Verwende
fuer Fliesstext (color: #374151; line-height: 1.65; font-size: 15px)
+- Verwende
als Trenner
+
+Fuer "summary": Kompakter Plaintext ohne HTML/Markdown. Abschnitte mit Zeilenumbruechen trennen.
Gespräch:
{conversation}
-Antworte auf Deutsch, sachlich und kompakt."""
+Antworte auf Deutsch, sachlich und kompakt. NUR JSON, keine Erklaerungen."""
def buildScoringPrompt(messages: List[Dict[str, Any]], contextCategory: str) -> str: