fixed build
This commit is contained in:
parent
18e6b3e4d8
commit
275164e7cb
4 changed files with 49 additions and 53 deletions
45
src/global.d.ts
vendored
Normal file
45
src/global.d.ts
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
interface SpeechRecognition extends EventTarget {
|
||||
continuous: boolean;
|
||||
interimResults: boolean;
|
||||
lang: string;
|
||||
onstart: ((this: SpeechRecognition, ev: Event) => void) | null;
|
||||
onend: ((this: SpeechRecognition, ev: Event) => void) | null;
|
||||
onerror: ((this: SpeechRecognition, ev: SpeechRecognitionErrorEvent) => void) | null;
|
||||
onresult: ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => void) | null;
|
||||
onspeechstart: ((this: SpeechRecognition, ev: Event) => void) | null;
|
||||
onspeechend: ((this: SpeechRecognition, ev: Event) => void) | null;
|
||||
start(): void;
|
||||
stop(): void;
|
||||
abort(): void;
|
||||
}
|
||||
|
||||
interface SpeechRecognitionErrorEvent extends Event {
|
||||
error: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface SpeechRecognitionEvent extends Event {
|
||||
resultIndex: number;
|
||||
results: SpeechRecognitionResultList;
|
||||
}
|
||||
|
||||
interface SpeechRecognitionResultList {
|
||||
length: number;
|
||||
[index: number]: SpeechRecognitionResult;
|
||||
}
|
||||
|
||||
interface SpeechRecognitionResult {
|
||||
isFinal: boolean;
|
||||
length: number;
|
||||
[index: number]: SpeechRecognitionAlternative;
|
||||
}
|
||||
|
||||
interface SpeechRecognitionAlternative {
|
||||
transcript: string;
|
||||
confidence: number;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
SpeechRecognition: new () => SpeechRecognition;
|
||||
webkitSpeechRecognition: new () => SpeechRecognition;
|
||||
}
|
||||
|
|
@ -9,10 +9,9 @@ import { useApiRequest } from './useApi';
|
|||
import { useInstanceId } from './useCurrentInstance';
|
||||
import {
|
||||
getContextsApi, createContextApi, getContextDetailApi,
|
||||
startSessionStreamApi, getSessionApi, completeSessionApi, cancelSessionApi,
|
||||
startSessionStreamApi, completeSessionApi, cancelSessionApi,
|
||||
sendMessageStreamApi, sendAudioStreamApi,
|
||||
getTasksApi, createTaskApi, updateTaskStatusApi, deleteTaskApi,
|
||||
getProfileApi, testVoiceApi,
|
||||
createTaskApi, updateTaskStatusApi, deleteTaskApi,
|
||||
type CoachingContext, type CoachingSession, type CoachingMessage,
|
||||
type CoachingTask, type CoachingScore, type SSEEvent,
|
||||
} from '../api/commcoachApi';
|
||||
|
|
@ -84,45 +83,9 @@ export function useCommcoach(): CommcoachHookReturn {
|
|||
const isMountedRef = useRef(true);
|
||||
const currentAudioRef = useRef<HTMLAudioElement | null>(null);
|
||||
const isTtsPlayingRef = useRef(false);
|
||||
const profileRef = useRef<{ preferredLanguage?: string; preferredVoice?: string } | null>(null);
|
||||
|
||||
useEffect(() => { isMountedRef.current = true; return () => { isMountedRef.current = false; }; }, []);
|
||||
|
||||
const _speakText = useCallback(async (text: string) => {
|
||||
if (!instanceId) return;
|
||||
const plain = _stripMarkdownForTts(text);
|
||||
if (!plain.trim()) return;
|
||||
if (currentAudioRef.current) {
|
||||
currentAudioRef.current.pause();
|
||||
currentAudioRef.current = null;
|
||||
}
|
||||
try {
|
||||
let profile = profileRef.current;
|
||||
if (!profile) {
|
||||
const p = await getProfileApi(request, instanceId);
|
||||
profile = { preferredLanguage: p?.preferredLanguage || 'de-DE', preferredVoice: p?.preferredVoice };
|
||||
profileRef.current = profile;
|
||||
}
|
||||
const lang = profile?.preferredLanguage || 'de-DE';
|
||||
const voiceId = profile?.preferredVoice || undefined;
|
||||
const result = await testVoiceApi(request, instanceId, { text: plain, language: lang, voiceId });
|
||||
if (result?.success && result?.audio && isMountedRef.current) {
|
||||
const audio = new Audio(`data:audio/mp3;base64,${result.audio}`);
|
||||
currentAudioRef.current = audio;
|
||||
audio.onended = () => { currentAudioRef.current = null; };
|
||||
try {
|
||||
await audio.play();
|
||||
} catch (playErr: any) {
|
||||
if (playErr?.name === 'NotAllowedError') {
|
||||
console.warn('CommCoach TTS: Browser blocked audio. Click "Session starten" or "Senden" first.');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// TTS failed silently, text is still visible
|
||||
}
|
||||
}, [request, instanceId]);
|
||||
|
||||
const refreshContexts = useCallback(async () => {
|
||||
if (!instanceId) return;
|
||||
setLoadingContexts(true);
|
||||
|
|
@ -520,8 +483,6 @@ export function useCommcoach(): CommcoachHookReturn {
|
|||
|
||||
useEffect(() => { if (instanceId) refreshContexts(); }, [instanceId, refreshContexts]);
|
||||
|
||||
useEffect(() => { profileRef.current = null; }, [instanceId]);
|
||||
|
||||
return {
|
||||
contexts, selectedContextId, selectedContext, loadingContexts,
|
||||
session, messages, isStreaming, streamingStatus,
|
||||
|
|
@ -536,16 +497,6 @@ export function useCommcoach(): CommcoachHookReturn {
|
|||
};
|
||||
}
|
||||
|
||||
function _stripMarkdownForTts(text: string): string {
|
||||
return text
|
||||
.replace(/\*\*(.+?)\*\*/g, '$1')
|
||||
.replace(/\*(.+?)\*/g, '$1')
|
||||
.replace(/\[(.+?)\]\(.+?\)/g, '$1')
|
||||
.replace(/^#+\s*/gm, '')
|
||||
.replace(/`[^`]+`/g, (m) => m.slice(1, -1))
|
||||
.trim();
|
||||
}
|
||||
|
||||
async function _unlockAudioForTts(): Promise<void> {
|
||||
try {
|
||||
const ctx = new (window.AudioContext || (window as any).webkitAudioContext)();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import styles from './CommcoachDashboardView.module.css';
|
|||
export const CommcoachDashboardView: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { mandateId, instanceId } = useCurrentInstance();
|
||||
const { dashboard, profile, loading, error, refresh } = useCommcoachDashboard();
|
||||
const { dashboard, loading, error } = useCommcoachDashboard();
|
||||
|
||||
const handleContextClick = (contextId: string) => {
|
||||
if (mandateId && instanceId) {
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ export const CommcoachDossierView: React.FC = () => {
|
|||
|
||||
interface ScoreGroup {
|
||||
dimension: string;
|
||||
latest: { score: number; trend: string; evidence?: string };
|
||||
latest: { score: number; trend: string; evidence?: string; createdAt?: string };
|
||||
history: Array<{ score: number; createdAt?: string }>;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue