fixed coaching rules

This commit is contained in:
ValueOn AG 2026-03-02 21:10:36 +01:00
parent 0518ee48d5
commit 18e6b3e4d8
2 changed files with 33 additions and 8 deletions

View file

@ -268,6 +268,12 @@
border-bottom-right-radius: 4px;
}
.messageLive {
opacity: 0.7;
font-style: italic;
border: 1px dashed rgba(255, 255, 255, 0.4);
}
.messageAssistant .messageBubble {
background: var(--bg-card, #f5f5f5);
color: var(--text-primary, #333);

View file

@ -28,6 +28,7 @@ export const CommcoachCoachingView: React.FC = () => {
const transcriptPartsRef = useRef<string[]>([]);
const [isListening, setIsListening] = useState(false);
const [isUserSpeaking, setIsUserSpeaking] = useState(false);
const [liveTranscript, setLiveTranscript] = useState('');
const handleSend = useCallback(async () => {
if (!coach.inputValue.trim() || coach.isStreaming) return;
@ -124,16 +125,26 @@ export const CommcoachCoachingView: React.FC = () => {
if (cancelled) return;
setIsUserSpeaking(true);
transcriptPartsRef.current = [];
setLiveTranscript('');
};
recognition.onresult = (event: SpeechRecognitionEvent) => {
if (cancelled) return;
const result = event.results[event.resultIndex];
if (!result.isFinal) return;
const transcript = result[0].transcript.trim();
if (transcript) transcriptPartsRef.current.push(transcript);
const wordCount = transcript.split(/\s+/).filter(Boolean).length;
if (wordCount >= MIN_WORDS_TO_INTERRUPT) coach.stopTts();
const finalized: string[] = [];
let currentInterim = '';
for (let i = 0; i < event.results.length; i++) {
const r = event.results[i];
if (r.isFinal) {
finalized.push(r[0].transcript.trim());
} else {
currentInterim = r[0].transcript.trim();
}
}
transcriptPartsRef.current = finalized.filter(Boolean);
const preview = [...transcriptPartsRef.current, currentInterim].join(' ').trim();
setLiveTranscript(preview);
const totalWords = preview.split(/\s+/).filter(Boolean).length;
if (totalWords >= MIN_WORDS_TO_INTERRUPT) coach.stopTts();
};
recognition.onspeechend = () => {
@ -144,6 +155,7 @@ export const CommcoachCoachingView: React.FC = () => {
if (wordCount >= MIN_WORDS_TO_INTERRUPT) coach.sendMessage(fullTranscript);
}
transcriptPartsRef.current = [];
setLiveTranscript('');
setIsUserSpeaking(false);
};
@ -302,7 +314,7 @@ export const CommcoachCoachingView: React.FC = () => {
</div>
</div>
<AutoScroll scrollDependency={coach.messages.length + (coach.isStreaming ? 1 : 0)}>
<AutoScroll scrollDependency={coach.messages.length + (coach.isStreaming ? 1 : 0) + liveTranscript.length}>
<div className={styles.messages}>
{coach.messages.map(msg => (
<div
@ -319,6 +331,13 @@ export const CommcoachCoachingView: React.FC = () => {
</div>
</div>
))}
{liveTranscript && (
<div className={`${styles.message} ${styles.messageUser}`}>
<div className={`${styles.messageBubble} ${styles.messageLive}`}>
{liveTranscript}
</div>
</div>
)}
{coach.isStreaming && (
<div className={`${styles.message} ${styles.messageAssistant}`}>
<div className={styles.messageBubble}>
@ -341,7 +360,7 @@ export const CommcoachCoachingView: React.FC = () => {
: coach.isStreaming
? (coach.streamingStatus || 'Coach antwortet...')
: isUserSpeaking
? 'Aufnahme...'
? 'Spricht...'
: isListening
? 'Mikrofon an bitte sprechen'
: 'Mikrofon wird gestartet...'}