File size: 2,319 Bytes
bd2b21f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
let utterance: SpeechSynthesisUtterance | null = null;

export function speak(text: string): void {
  if (!('speechSynthesis' in window)) {
    console.warn('Speech synthesis not supported');
    return;
  }

  window.speechSynthesis.cancel();

  utterance = new SpeechSynthesisUtterance(text);
  utterance.rate = 1.0;
  utterance.pitch = 1.0;
  utterance.volume = 1.0;

  const voices = window.speechSynthesis.getVoices();
  const englishVoice = voices.find(v => v.lang.startsWith('en') && v.name.includes('Google')) ||
                       voices.find(v => v.lang.startsWith('en'));
  if (englishVoice) {
    utterance.voice = englishVoice;
  }

  window.speechSynthesis.speak(utterance);
}

export function stopSpeaking(): void {
  if ('speechSynthesis' in window) {
    window.speechSynthesis.cancel();
  }
}

export function isSpeaking(): boolean {
  if (!('speechSynthesis' in window)) return false;
  return window.speechSynthesis.speaking;
}

export function getAvailableVoices(): SpeechSynthesisVoice[] {
  if (!('speechSynthesis' in window)) return [];
  return window.speechSynthesis.getVoices().filter(v => v.lang.startsWith('en'));
}

export function formatDirectionForSpeech(instruction: string): string {
  return instruction
    .replace(/onto/gi, 'onto')
    .replace(/Continue/gi, 'Continue')
    .replace(/Turn left/gi, 'Turn left')
    .replace(/Turn right/gi, 'Turn right')
    .replace(/Slight left/gi, 'Bear left')
    .replace(/Slight right/gi, 'Bear right')
    .replace(/km/g, 'kilometers')
    .replace(/m/g, 'meters')
    .trim();
}

export function speakDirection(step: { maneuver: { type?: string; modifier?: string; instruction?: string; name?: string }; distance?: number }): void {
  let text = '';

  if (step.maneuver.instruction) {
    text = formatDirectionForSpeech(step.maneuver.instruction);
  } else {
    const type = step.maneuver.type || '';
    const modifier = step.maneuver.modifier || '';
    const name = step.maneuver.name || '';
    text = `${type} ${modifier}`.trim();
    if (name) text += ` onto ${name}`;
  }

  if (step.distance && step.distance > 0) {
    const distText = step.distance >= 1000
      ? `${(step.distance / 1000).toFixed(1)} kilometers`
      : `${Math.round(step.distance)} meters`;
    text += `. Then go ${distText}.`;
  }

  speak(text);
}