commcoach iteration 1 completed

This commit is contained in:
ValueOn AG 2026-03-03 22:04:54 +01:00
parent 275164e7cb
commit cd14e8a6fb
4 changed files with 32 additions and 10 deletions

View file

@ -99,7 +99,8 @@ export interface DashboardData {
recentScores: CoachingScore[]; recentScores: CoachingScore[];
openTasks: number; openTasks: number;
completedTasks: number; completedTasks: number;
contexts: Array<{ id: string; title: string; category: string; sessionCount: number; lastSessionAt?: string }>; goalProgress?: number;
contexts: Array<{ id: string; title: string; category: string; sessionCount: number; lastSessionAt?: string; goalProgress?: number }>;
} }
export interface SSEEvent { export interface SSEEvent {

View file

@ -26,6 +26,7 @@ export interface CommcoachHookReturn {
messages: CoachingMessage[]; messages: CoachingMessage[];
isStreaming: boolean; isStreaming: boolean;
streamingStatus: string | null; streamingStatus: string | null;
streamingMessage: string | null;
tasks: CoachingTask[]; tasks: CoachingTask[];
scores: CoachingScore[]; scores: CoachingScore[];
@ -70,6 +71,7 @@ export function useCommcoach(): CommcoachHookReturn {
const [messages, setMessages] = useState<CoachingMessage[]>([]); const [messages, setMessages] = useState<CoachingMessage[]>([]);
const [isStreaming, setIsStreaming] = useState(false); const [isStreaming, setIsStreaming] = useState(false);
const [streamingStatus, setStreamingStatus] = useState<string | null>(null); const [streamingStatus, setStreamingStatus] = useState<string | null>(null);
const [streamingMessage, setStreamingMessage] = useState<string | null>(null);
const [tasks, setTasks] = useState<CoachingTask[]>([]); const [tasks, setTasks] = useState<CoachingTask[]>([]);
const [scores, setScores] = useState<CoachingScore[]>([]); const [scores, setScores] = useState<CoachingScore[]>([]);
@ -237,7 +239,10 @@ export function useCommcoach(): CommcoachHookReturn {
if (eventData.resumed && Array.isArray(eventData.messages)) { if (eventData.resumed && Array.isArray(eventData.messages)) {
setMessages(eventData.messages); setMessages(eventData.messages);
} }
} else if (eventType === 'messageChunk' && eventData) {
setStreamingMessage(eventData.accumulated || '');
} else if (eventType === 'message' && eventData) { } else if (eventType === 'message' && eventData) {
setStreamingMessage(null);
const msg: CoachingMessage = { const msg: CoachingMessage = {
id: eventData.id || `msg-${Date.now()}`, id: eventData.id || `msg-${Date.now()}`,
sessionId: eventData.sessionId || '', sessionId: eventData.sessionId || '',
@ -263,12 +268,14 @@ export function useCommcoach(): CommcoachHookReturn {
if (isMountedRef.current) { if (isMountedRef.current) {
setError(err.message); setError(err.message);
setIsStreaming(false); setIsStreaming(false);
setStreamingMessage(null);
} }
}, },
() => { () => {
if (isMountedRef.current) { if (isMountedRef.current) {
setIsStreaming(false); setIsStreaming(false);
setStreamingStatus(null); setStreamingStatus(null);
setStreamingMessage(null);
} }
}, },
); );
@ -309,7 +316,10 @@ export function useCommcoach(): CommcoachHookReturn {
const eventType = event.type; const eventType = event.type;
const eventData = event.data; const eventData = event.data;
if (eventType === 'message' && eventData) { if (eventType === 'messageChunk' && eventData) {
setStreamingMessage(eventData.accumulated || '');
} else if (eventType === 'message' && eventData) {
setStreamingMessage(null);
const msg: CoachingMessage = { const msg: CoachingMessage = {
id: eventData.id || `msg-${Date.now()}`, id: eventData.id || `msg-${Date.now()}`,
sessionId: session.id, sessionId: session.id,
@ -343,12 +353,14 @@ export function useCommcoach(): CommcoachHookReturn {
if (isMountedRef.current) { if (isMountedRef.current) {
setError(err.message); setError(err.message);
setIsStreaming(false); setIsStreaming(false);
setStreamingMessage(null);
} }
}, },
() => { () => {
if (isMountedRef.current) { if (isMountedRef.current) {
setIsStreaming(false); setIsStreaming(false);
setStreamingStatus(null); setStreamingStatus(null);
setStreamingMessage(null);
} }
}, },
); );
@ -485,7 +497,7 @@ export function useCommcoach(): CommcoachHookReturn {
return { return {
contexts, selectedContextId, selectedContext, loadingContexts, contexts, selectedContextId, selectedContext, loadingContexts,
session, messages, isStreaming, streamingStatus, session, messages, isStreaming, streamingStatus, streamingMessage,
tasks, scores, sessions, tasks, scores, sessions,
error, inputValue, setInputValue, error, inputValue, setInputValue,
selectContext, createContext, archiveContext, selectContext, createContext, archiveContext,

View file

@ -341,10 +341,16 @@ export const CommcoachCoachingView: React.FC = () => {
{coach.isStreaming && ( {coach.isStreaming && (
<div className={`${styles.message} ${styles.messageAssistant}`}> <div className={`${styles.message} ${styles.messageAssistant}`}>
<div className={styles.messageBubble}> <div className={styles.messageBubble}>
<div className={styles.typing}> {coach.streamingMessage ? (
{coach.streamingStatus || 'Coach denkt nach'} <ReactMarkdown remarkPlugins={[remarkGfm]}>
<span className={styles.typingDots}>...</span> {coach.streamingMessage}
</div> </ReactMarkdown>
) : (
<div className={styles.typing}>
{coach.streamingStatus || 'Coach denkt nach'}
<span className={styles.typingDots}>...</span>
</div>
)}
</div> </div>
</div> </div>
)} )}

View file

@ -55,9 +55,11 @@ export const CommcoachDashboardView: React.FC = () => {
<div className={styles.kpiSub}>Durchschnitt</div> <div className={styles.kpiSub}>Durchschnitt</div>
</div> </div>
<div className={styles.kpiCard}> <div className={styles.kpiCard}>
<div className={styles.kpiValue}>{dashboard.openTasks}</div> <div className={styles.kpiValue}>
<div className={styles.kpiLabel}>Offene Aufgaben</div> {dashboard.goalProgress != null ? `${dashboard.goalProgress}%` : '--'}
<div className={styles.kpiSub}>{dashboard.completedTasks} erledigt</div> </div>
<div className={styles.kpiLabel}>Zielfortschritt</div>
<div className={styles.kpiSub}>{dashboard.openTasks} offene Aufgaben</div>
</div> </div>
</div> </div>
@ -84,6 +86,7 @@ export const CommcoachDashboardView: React.FC = () => {
<div className={styles.contextMeta}> <div className={styles.contextMeta}>
<span className={styles.contextCategory}>{_categoryLabel(ctx.category)}</span> <span className={styles.contextCategory}>{_categoryLabel(ctx.category)}</span>
<span>{ctx.sessionCount} Sessions</span> <span>{ctx.sessionCount} Sessions</span>
{ctx.goalProgress != null && <span>Ziele: {ctx.goalProgress}%</span>}
</div> </div>
{ctx.lastSessionAt && ( {ctx.lastSessionAt && (
<div className={styles.contextLast}> <div className={styles.contextLast}>