From b6c01fd203b3acd6fa23c7ad1a426190f1e302d5 Mon Sep 17 00:00:00 2001
From: patrick-motsch
Date: Sat, 7 Mar 2026 02:09:30 +0100
Subject: [PATCH] commcoach: fix double extensions, improve AI document
generation quality and action prompts
Made-with: Cursor
---
.../features/commcoach/serviceCommcoach.py | 22 ++++++++++++++++---
.../features/commcoach/serviceCommcoachAi.py | 19 +++++++++++++---
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/modules/features/commcoach/serviceCommcoach.py b/modules/features/commcoach/serviceCommcoach.py
index 8151d343..38a1893e 100644
--- a/modules/features/commcoach/serviceCommcoach.py
+++ b/modules/features/commcoach/serviceCommcoach.py
@@ -178,6 +178,21 @@ async def _generateAndEmitTts(sessionId: str, speechText: str, currentUser, mand
logger.warning(f"TTS failed for session {sessionId}: {e}")
+def _resolveFileNameAndMime(title: str) -> tuple:
+ """Derive fileName and mimeType from a document title. Only appends .md if no known extension present."""
+ import os
+ knownExtensions = {
+ ".md": "text/markdown", ".txt": "text/plain", ".html": "text/html",
+ ".htm": "text/html", ".pdf": "application/pdf", ".json": "application/json",
+ ".csv": "text/csv", ".xml": "application/xml", ".doc": "application/msword",
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ }
+ _, ext = os.path.splitext(title)
+ if ext.lower() in knownExtensions:
+ return title, knownExtensions[ext.lower()]
+ return f"{title}.md", "text/markdown"
+
+
async def _saveOrUpdateDocument(doc: Dict[str, Any], contextId: str, userId: str,
mandateId: str, instanceId: str, interface, sessionId: str,
user=None):
@@ -188,7 +203,7 @@ async def _saveOrUpdateDocument(doc: Dict[str, Any], contextId: str, userId: str
title = doc.get("title", "Dokument")
content = doc.get("content", "")
contentBytes = content.encode("utf-8")
- fileName = f"{title}.md"
+ fileName, mimeType = _resolveFileNameAndMime(title)
fileRef = None
try:
@@ -196,7 +211,7 @@ async def _saveOrUpdateDocument(doc: Dict[str, Any], contextId: str, userId: str
mgmtInterface = interfaceDbManagement.getInterface(
currentUser=user, mandateId=mandateId, featureInstanceId=instanceId
)
- fileItem = mgmtInterface.createFile(name=fileName, mimeType="text/markdown", content=contentBytes)
+ fileItem = mgmtInterface.createFile(name=fileName, mimeType=mimeType, content=contentBytes)
mgmtInterface.createFileData(fileItem.id, contentBytes)
fileRef = fileItem.id
except Exception as e:
@@ -205,6 +220,7 @@ async def _saveOrUpdateDocument(doc: Dict[str, Any], contextId: str, userId: str
if docId:
updates = {
"fileName": fileName,
+ "mimeType": mimeType,
"extractedText": content,
"summary": title,
"fileSize": len(contentBytes),
@@ -224,7 +240,7 @@ async def _saveOrUpdateDocument(doc: Dict[str, Any], contextId: str, userId: str
mandateId=mandateId,
instanceId=instanceId,
fileName=fileName,
- mimeType="text/markdown",
+ mimeType=mimeType,
fileSize=len(contentBytes),
extractedText=content,
summary=title,
diff --git a/modules/features/commcoach/serviceCommcoachAi.py b/modules/features/commcoach/serviceCommcoachAi.py
index 8db9e61c..7ba52f58 100644
--- a/modules/features/commcoach/serviceCommcoachAi.py
+++ b/modules/features/commcoach/serviceCommcoachAi.py
@@ -160,22 +160,35 @@ Kommunikationsstil:
- Sei direkt aber wertschätzend
- Verwende keine Emojis
- Antworte in der Sprache des Benutzers
-- Halte Antworten fokussiert (max 3-4 Absätze)"""
+- Halte Chat-Antworten (text/speech) fokussiert. Dokumente duerfen ausfuehrlich sein."""
prompt += """
+Handlungsprinzip:
+- Wenn der Benutzer dich bittet, etwas zu erstellen (Dokument, Präsentation, Checkliste, Plan), dann TU ES SOFORT. Frage NICHT nochmals nach Bestätigung.
+- Verwende alle verfügbaren Informationen aus dem Chat-Verlauf, den Dokumenten und dem Kontext.
+- Wenn der Benutzer sagt "erstelle", "mach", "schreib", dann liefere das fertige Ergebnis — keine Aufzählung von Punkten, die du "gleich umsetzen wirst".
+
Antwortformat:
Du antwortest IMMER als reines JSON-Objekt mit exakt diesen Feldern:
{"text": "...", "speech": "...", "documents": []}
"text": Dein schriftlicher Chat-Text. Details, Struktur, Übungen, Beispiele. Markdown-Formatierung erlaubt.
"speech": Dein gesprochener Kommentar. Natürlich, wie ein Gespräch. Fasse zusammen, kommentiere, motiviere, stelle Fragen. Lies NICHT den Text vor, ergänze ihn mündlich. 2-4 Sätze, reiner Redetext ohne Formatierung.
-"documents": Dokumente (Zusammenfassungen, Checklisten, Übungen, Protokolle). Erstelle ein Dokument wenn: der Benutzer explizit darum bittet, du strukturierte Inhalte (Listen, Pläne, Checklisten) lieferst, oder Material zum Aufbewahren sinnvoll ist. Jedes Dokument: {"title": "...", "content": "Markdown-Inhalt"}. Wenn keine: leeres Array [].
+"documents": Dokumente die der Benutzer aufbewahren kann. Erstelle ein Dokument wenn: der Benutzer explizit darum bittet, du strukturierte Inhalte lieferst, oder Material zum Aufbewahren sinnvoll ist. Wenn keine: leeres Array [].
+
+Dokument-Format:
+{"title": "Dateiname_mit_Extension.html", "content": "...vollstaendiger Inhalt..."}
+- Der Title IST der Dateiname inkl. Extension (.html, .md, .txt etc.)
+- Fuer HTML-Dokumente: Erstelle VOLLSTAENDIGES, professionell gestyltes HTML mit inline CSS. Kein Markdown, sondern fertiges HTML mit Farben, Layout, Typografie.
+- Fuer andere Dokumente: Verwende Markdown.
+- WICHTIG: Der Content muss VOLLSTAENDIG und AUSFUEHRLICH sein. Keine Platzhalter, keine "hier kommt..."-Abschnitte. Schreibe echte, detaillierte Inhalte basierend auf allen verfuegbaren Informationen aus dem Chat und den Dokumenten.
+- Laengenbeschraenkung fuer Dokumente: KEINE. Schreibe so viel wie noetig fuer ein vollstaendiges Ergebnis.
Kanalverteilung:
- Fakten, Listen, Übungen -> text
- Empathie, Einordnung, Nachfragen -> speech
-- Materialien zum Aufbewahren -> documents
+- Erstellte Dateien, Materialien zum Aufbewahren -> documents
WICHTIG: Antworte NUR mit dem JSON-Objekt. Kein Text vor oder nach dem JSON."""