@readium/speech 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ The outline of this work has been explored in a [GitHub discussion](https://gith
24
24
  In the second phase, we focused on implementing a WebSpeech API-based solution with an architecture designed for future extensibility:
25
25
 
26
26
  - **Engine Layer**: Core TTS functionality through `ReadiumSpeechPlaybackEngine`
27
- - **Navigator Layer**: Content and playback management via (a temporary) `ReadiumSpeechNavigator`
27
+ - **Navigator Layer**: Content and playback management via `ReadiumSpeechNavigator`
28
28
  - **Current Implementation**: WebSpeech API with cross-browser compatibility
29
29
  - **Future-Proof Design**: Architecture prepared for additional TTS service adapters
30
30
 
@@ -32,7 +32,9 @@ Key features include advanced voice selection, cross-browser playback control, f
32
32
 
33
33
  In the third phase, we added highlighting: content currently being spoken (e.g. the current word or sentence) can be highlighted as playback progresses. See the [Highlighting guide](docs/Highlighting.md).
34
34
 
35
- We are now focused on the fourth phase: extracting [Guided Navigation objects](https://readium.org/guided-navigation) from a document (or a fragment of a document), and generating utterances from these objects.
35
+ In the fourth phase, we extracted [Guided Navigation objects](https://readium.org/guided-navigation) from a document (or a fragment of a document), and generated utterances from these objects.
36
+
37
+ We are now on the fifth phase: a second `ReadiumSpeechPlaybackEngine` implementation, backed by [speech-server](https://github.com/readium/speech-server) instead of the browser's Web Speech API.
36
38
 
37
39
  ## Demos
38
40
 
@@ -78,7 +80,8 @@ yarn add @readium/speech
78
80
  ```typescript
79
81
  import {
80
82
  WebSpeechVoiceManager,
81
- WebSpeechReadAloudNavigator,
83
+ WebSpeechEngine,
84
+ ReadiumSpeechNavigator,
82
85
  setupDecorations,
83
86
  DecorationStyleType,
84
87
  } from "@readium/speech";
@@ -92,7 +95,7 @@ const voiceManager = await WebSpeechVoiceManager.initialize({
92
95
  const voice = await voiceManager.getDefaultVoice("en-US");
93
96
 
94
97
  // Create a navigator instance
95
- const navigator = new WebSpeechReadAloudNavigator();
98
+ const navigator = new ReadiumSpeechNavigator(new WebSpeechEngine());
96
99
  await navigator.setVoice(voice);
97
100
 
98
101
  const content = document.getElementById("content");
@@ -137,6 +140,7 @@ Documentation provides guides for:
137
140
  - [Highlighting](docs/Highlighting.md)
138
141
  - [Guided Navigation](docs/GuidedNavigation.md) — extracting [Guided Navigation objects](https://readium.org/guided-navigation) from HTML/XHTML content
139
142
  - [Utterance Extraction](docs/UtteranceExtraction.md) — extracting utterances from Guided Navigation objects
143
+ - [Provider Registry](docs/ProviderRegistry.md) — using more than one `ReadiumSpeechEngineProvider` (e.g. WebSpeech and speech-server) side by side
140
144
 
141
145
  ## Development
142
146
 
@@ -0,0 +1,6 @@
1
+ export interface TextChunk {
2
+ text: string;
3
+ offset: number;
4
+ }
5
+ export declare function chunkPlainText(text: string, maxLength: number): TextChunk[];
6
+ export declare function chunkSsmlText(text: string, maxLength: number): TextChunk[];
@@ -0,0 +1,20 @@
1
+ export interface SpeechServerProblemDetails {
2
+ type: string;
3
+ title: string;
4
+ status: number;
5
+ detail: string;
6
+ instance?: string;
7
+ }
8
+ export declare class SpeechServerError extends Error {
9
+ readonly status: number;
10
+ readonly type?: string;
11
+ readonly title?: string;
12
+ readonly instance?: string;
13
+ constructor(message: string, options: {
14
+ status: number;
15
+ type?: string;
16
+ title?: string;
17
+ instance?: string;
18
+ });
19
+ }
20
+ export declare function toSpeechServerError(response: Response): Promise<SpeechServerError>;
@@ -0,0 +1,7 @@
1
+ export * from './chunkText';
2
+ export * from './selectFormat';
3
+ export * from './speechServerEngine';
4
+ export * from './speechServerEngineProvider';
5
+ export * from './speechServerVoiceMapping';
6
+ export * from './errors';
7
+ export * from './types';
@@ -0,0 +1,18 @@
1
+ import { SpeechServerAudioFormat } from './types';
2
+ export type CanPlayTypeResult = "probably" | "maybe" | "";
3
+ export type CanPlayType = (mime: string) => CanPlayTypeResult;
4
+ export declare function mimeTypeForFormat(format: string): string;
5
+ export interface SpeechServerFormatOptions {
6
+ preferredFormat?: SpeechServerAudioFormat | (string & {});
7
+ strategy?: "quality" | "bandwidth";
8
+ adaptBitrateToNetwork?: boolean;
9
+ }
10
+ export declare function selectFormat(output: {
11
+ formats: string[];
12
+ default: string;
13
+ }, options: Pick<SpeechServerFormatOptions, "preferredFormat" | "strategy">, canPlay: CanPlayType): string;
14
+ export interface NetworkInfo {
15
+ saveData?: boolean;
16
+ effectiveType?: string;
17
+ }
18
+ export declare function selectBitrate(format: string, adaptBitrateToNetwork: boolean, network: NetworkInfo | undefined): number | undefined;
@@ -0,0 +1,91 @@
1
+ import { ReadiumSpeechPlaybackEngine } from '../engine';
2
+ import { ReadiumSpeechPlaybackEvent, ReadiumSpeechPlaybackState } from '../navigator';
3
+ import { ReadiumSpeechUtterance } from '../utterance';
4
+ import { ReadiumSpeechVoice } from '../voices/types';
5
+ import { SpeechServerFormatOptions } from './selectFormat';
6
+ export interface SpeechServerEndpoints {
7
+ voices: string;
8
+ synthesize: string;
9
+ service: string;
10
+ }
11
+ export interface SpeechServerEngineOptions {
12
+ endpoints: SpeechServerEndpoints;
13
+ fetch?: typeof fetch;
14
+ prefetchWindow?: number;
15
+ readyBufferChars?: number;
16
+ overLengthText?: "split" | "error";
17
+ format?: SpeechServerFormatOptions;
18
+ }
19
+ export declare class SpeechServerEngine implements ReadiumSpeechPlaybackEngine {
20
+ private endpoints;
21
+ private fetchImpl;
22
+ private currentVoice;
23
+ private voices;
24
+ private serviceInfo;
25
+ private serviceInfoPromise;
26
+ private currentUtterances;
27
+ private currentUtteranceIndex;
28
+ private playbackState;
29
+ private eventListeners;
30
+ private speakInContentLanguage;
31
+ private speakGeneration;
32
+ private loadGeneration;
33
+ private readonly prefetchWindow;
34
+ private readonly readyBufferChars;
35
+ private readonly overLengthText;
36
+ private readonly formatOptions;
37
+ private readonly canPlayType;
38
+ private prefetchCache;
39
+ private prefetchChainTail;
40
+ private audioContext;
41
+ private masterGain;
42
+ private scheduledChunks;
43
+ private boundaryRafHandle;
44
+ private rate;
45
+ private pitch;
46
+ private volume;
47
+ constructor(options: SpeechServerEngineOptions);
48
+ setAvailableVoices(voices: ReadiumSpeechVoice[]): void;
49
+ loadUtterances(contents: ReadiumSpeechUtterance[]): void;
50
+ private bufferUntilReady;
51
+ private indexCoveringChars;
52
+ setVoice(voice: ReadiumSpeechVoice | string): void;
53
+ getCurrentVoice(): ReadiumSpeechVoice | null;
54
+ getAvailableVoices(): Promise<ReadiumSpeechVoice[]>;
55
+ private getServiceInfo;
56
+ private fetchServiceInfo;
57
+ setSpeakInContentLanguage(enabled: boolean): void;
58
+ getSpeakInContentLanguage(): boolean;
59
+ speak(utteranceIndex?: number): void;
60
+ private synthesizeAndPlay;
61
+ private resolveSynthesisStream;
62
+ private fillPrefetchWindow;
63
+ private queuePrefetch;
64
+ private clearPrefetchCache;
65
+ private synthesizeStream;
66
+ private synthesizeChunk;
67
+ private ensureAudioContext;
68
+ private scheduleChunksStreaming;
69
+ private handleUtteranceEnded;
70
+ private startBoundaryPolling;
71
+ private stopBoundaryPolling;
72
+ private checkBoundaries;
73
+ private stopAudio;
74
+ pause(): void;
75
+ resume(): void;
76
+ stop(): void;
77
+ setRate(rate: number): void;
78
+ getRate(): number;
79
+ setPitch(pitch: number): void;
80
+ getPitch(): number;
81
+ setVolume(volume: number): void;
82
+ getVolume(): number;
83
+ getState(): ReadiumSpeechPlaybackState;
84
+ getCurrentUtteranceIndex(): number;
85
+ setCurrentUtteranceIndex(index: number, onComplete?: (success: boolean) => void): void;
86
+ getUtteranceCount(): number;
87
+ on(event: ReadiumSpeechPlaybackEvent["type"], callback: (event: ReadiumSpeechPlaybackEvent) => void): () => void;
88
+ private emitEvent;
89
+ private setState;
90
+ destroy(): Promise<void>;
91
+ }
@@ -0,0 +1,16 @@
1
+ import { ReadiumSpeechEngineProvider } from '../provider';
2
+ import { ReadiumSpeechPlaybackEngine } from '../engine';
3
+ import { ReadiumSpeechVoice } from '../voices/types';
4
+ import { SpeechServerEngineOptions } from './speechServerEngine';
5
+ export type SpeechServerEngineProviderOptions = SpeechServerEngineOptions;
6
+ export declare class SpeechServerEngineProvider implements ReadiumSpeechEngineProvider {
7
+ readonly id: string;
8
+ readonly name: string;
9
+ private options;
10
+ private fetchImpl;
11
+ private voices;
12
+ constructor(options: SpeechServerEngineProviderOptions);
13
+ getVoices(): Promise<ReadiumSpeechVoice[]>;
14
+ createEngine(voice?: ReadiumSpeechVoice | string): Promise<ReadiumSpeechPlaybackEngine>;
15
+ destroy(): Promise<void>;
16
+ }
@@ -0,0 +1,3 @@
1
+ import { ReadiumSpeechVoice } from '../voices/types';
2
+ import { SpeechServerVoice } from './types';
3
+ export declare function mapServerVoice(voice: SpeechServerVoice): ReadiumSpeechVoice;
@@ -0,0 +1,56 @@
1
+ import { TGender, TQuality, TServerVoiceControls } from '../voices/types';
2
+ export interface SpeechServerVoice {
3
+ name: string;
4
+ originalName: string;
5
+ provider: string;
6
+ identifier: string;
7
+ language: string;
8
+ otherLanguages?: string[];
9
+ gender?: TGender | null;
10
+ quality?: TQuality;
11
+ controls?: TServerVoiceControls;
12
+ }
13
+ export interface SpeechServerTimingMark {
14
+ name: "word" | "sentence";
15
+ charIndex: number;
16
+ charLength: number;
17
+ elapsedTime: number;
18
+ }
19
+ export type SpeechServerAudioFormat = "wav" | "mp3" | "opus" | "aac" | "flac" | "ogg" | "webm" | "m4a";
20
+ export interface SpeechServerSynthesizeRequest {
21
+ id?: string;
22
+ text: string;
23
+ ssml?: boolean;
24
+ language?: string;
25
+ voice?: string;
26
+ prev_utterance?: string;
27
+ next_utterance?: string;
28
+ publication_id?: string;
29
+ boundary?: boolean;
30
+ output?: {
31
+ format?: SpeechServerAudioFormat;
32
+ bitrate?: number | null;
33
+ sample_rate?: number | null;
34
+ speed?: number;
35
+ pitch?: number | null;
36
+ };
37
+ }
38
+ export interface SpeechServerSynthesizeBoundaryResponse {
39
+ audio: string;
40
+ format: SpeechServerAudioFormat;
41
+ boundaries: SpeechServerTimingMark[] | null;
42
+ }
43
+ export interface SpeechServerServiceInfo {
44
+ output: {
45
+ formats: SpeechServerAudioFormat[];
46
+ default: SpeechServerAudioFormat;
47
+ };
48
+ limits: {
49
+ maxTextLength: number;
50
+ maxConcurrentSyntheses: number;
51
+ };
52
+ providers: {
53
+ id: string;
54
+ installedLanguages: string[];
55
+ }[];
56
+ }
@@ -1,4 +1,3 @@
1
1
  export * from './WebSpeechVoiceManager';
2
2
  export * from './webSpeechEngine';
3
3
  export * from './webSpeechEngineProvider';
4
- export * from './TmpNavigator';
@@ -4,7 +4,7 @@ import { ReadiumSpeechVoice } from '../voices/types';
4
4
  export declare class WebSpeechEngineProvider implements ReadiumSpeechEngineProvider {
5
5
  readonly id: string;
6
6
  readonly name: string;
7
- private engine;
7
+ private voiceEngine;
8
8
  getVoices(): Promise<ReadiumSpeechVoice[]>;
9
9
  createEngine(voice?: ReadiumSpeechVoice | string): Promise<ReadiumSpeechPlaybackEngine>;
10
10
  destroy(): Promise<void>;
package/build/engine.d.ts CHANGED
@@ -2,6 +2,7 @@ import { ReadiumSpeechPlaybackEvent, ReadiumSpeechPlaybackState } from './naviga
2
2
  import { ReadiumSpeechUtterance } from './utterance';
3
3
  import { ReadiumSpeechVoice } from './voices/types';
4
4
  export interface ReadiumSpeechPlaybackEngine {
5
+ initialize?(): Promise<unknown>;
5
6
  loadUtterances(contents: ReadiumSpeechUtterance[]): void;
6
7
  setVoice(voice: ReadiumSpeechVoice | string): void;
7
8
  getCurrentVoice(): ReadiumSpeechVoice | null;