@cartesia/cartesia-js 0.0.4-alpha.0 → 1.0.0-alpha.2

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.
Files changed (89) hide show
  1. package/.turbo/turbo-build.log +63 -45
  2. package/CHANGELOG.md +12 -0
  3. package/README.md +123 -16
  4. package/dist/chunk-36JBKJUN.js +119 -0
  5. package/dist/chunk-3F5E46FT.js +212 -0
  6. package/dist/{chunk-XPIMIAAE.js → chunk-3FL2SNIR.js} +1 -1
  7. package/dist/chunk-JGP5BIUV.js +34 -0
  8. package/dist/chunk-KWBSQZTY.js +25 -0
  9. package/dist/chunk-PQ6CIPFW.js +120 -0
  10. package/dist/chunk-RO7TY474.js +81 -0
  11. package/dist/chunk-T3RG6WV4.js +22 -0
  12. package/dist/{chunk-R4P7LWVZ.js → chunk-WIFMLPT5.js} +31 -6
  13. package/dist/chunk-WVTITUXX.js +58 -0
  14. package/dist/chunk-XHTDPLFR.js +19 -0
  15. package/dist/index.cjs +425 -166
  16. package/dist/index.d.cts +7 -3
  17. package/dist/index.d.ts +7 -3
  18. package/dist/index.js +13 -6
  19. package/dist/lib/client.cjs +49 -1
  20. package/dist/lib/client.d.cts +2 -0
  21. package/dist/lib/client.d.ts +2 -0
  22. package/dist/lib/client.js +3 -3
  23. package/dist/lib/constants.cjs +15 -8
  24. package/dist/lib/constants.d.cts +4 -4
  25. package/dist/lib/constants.d.ts +4 -4
  26. package/dist/lib/constants.js +6 -6
  27. package/dist/lib/index.cjs +310 -171
  28. package/dist/lib/index.d.cts +6 -2
  29. package/dist/lib/index.d.ts +6 -2
  30. package/dist/lib/index.js +9 -6
  31. package/dist/react/index.cjs +573 -290
  32. package/dist/react/index.d.cts +20 -14
  33. package/dist/react/index.d.ts +20 -14
  34. package/dist/react/index.js +157 -105
  35. package/dist/react/utils.js +2 -2
  36. package/dist/tts/index.cjs +496 -0
  37. package/dist/tts/index.d.cts +17 -0
  38. package/dist/tts/index.d.ts +17 -0
  39. package/dist/tts/index.js +12 -0
  40. package/dist/tts/player.cjs +198 -0
  41. package/dist/tts/player.d.cts +43 -0
  42. package/dist/tts/player.d.ts +43 -0
  43. package/dist/tts/player.js +8 -0
  44. package/dist/tts/source.cjs +181 -0
  45. package/dist/tts/source.d.cts +53 -0
  46. package/dist/tts/source.d.ts +53 -0
  47. package/dist/tts/source.js +7 -0
  48. package/dist/{audio → tts}/utils.cjs +25 -60
  49. package/dist/tts/utils.d.cts +67 -0
  50. package/dist/tts/utils.d.ts +67 -0
  51. package/dist/{audio → tts}/utils.js +2 -7
  52. package/dist/tts/websocket.cjs +479 -0
  53. package/dist/tts/websocket.d.cts +53 -0
  54. package/dist/tts/websocket.d.ts +53 -0
  55. package/dist/tts/websocket.js +11 -0
  56. package/dist/types/index.d.cts +50 -1
  57. package/dist/types/index.d.ts +50 -1
  58. package/dist/voices/index.cjs +157 -0
  59. package/dist/voices/index.d.cts +12 -0
  60. package/dist/voices/index.d.ts +12 -0
  61. package/dist/voices/index.js +9 -0
  62. package/package.json +2 -1
  63. package/src/index.ts +1 -0
  64. package/src/lib/client.ts +15 -1
  65. package/src/lib/constants.ts +15 -4
  66. package/src/lib/index.ts +6 -3
  67. package/src/react/index.ts +176 -110
  68. package/src/tts/index.ts +17 -0
  69. package/src/tts/player.ts +110 -0
  70. package/src/tts/source.ts +115 -0
  71. package/src/tts/utils.ts +150 -0
  72. package/src/tts/websocket.ts +214 -0
  73. package/src/types/index.ts +63 -0
  74. package/src/voices/index.ts +47 -0
  75. package/dist/audio/index.cjs +0 -404
  76. package/dist/audio/index.d.cts +0 -5
  77. package/dist/audio/index.d.ts +0 -5
  78. package/dist/audio/index.js +0 -10
  79. package/dist/audio/utils.d.cts +0 -5
  80. package/dist/audio/utils.d.ts +0 -5
  81. package/dist/chunk-4MHF74A7.js +0 -272
  82. package/dist/chunk-5TSWLYOW.js +0 -113
  83. package/dist/chunk-MJIFZWHS.js +0 -18
  84. package/dist/chunk-OVI3W3GG.js +0 -12
  85. package/dist/chunk-S6A27RQL.js +0 -18
  86. package/dist/index-C2_3XFxn.d.cts +0 -163
  87. package/dist/index-DgwnZezj.d.ts +0 -163
  88. package/src/audio/index.ts +0 -297
  89. package/src/audio/utils.ts +0 -220
@@ -1,27 +1,33 @@
1
- import { C as Chunk, S as StreamEventData } from '../index-C2_3XFxn.cjs';
1
+ import Source from '../tts/source.cjs';
2
2
  import 'emittery';
3
- import 'partysocket';
4
- import '../lib/client.cjs';
5
3
  import '../types/index.cjs';
6
4
 
7
- type UseAudioOptions = {
5
+ type UseTTSOptions = {
8
6
  apiKey: string | null;
9
7
  baseUrl?: string;
8
+ sampleRate: number;
10
9
  };
11
- interface UseAudioReturn {
12
- stream: (options: object) => void;
10
+ type PlaybackStatus = "inactive" | "playing" | "paused" | "finished";
11
+ type BufferStatus = "inactive" | "buffering" | "buffered";
12
+ type Metrics = {
13
+ modelLatency: number | null;
14
+ };
15
+ interface UseTTSReturn {
16
+ buffer: (options: object) => Promise<void>;
13
17
  play: (bufferDuration?: number) => Promise<void>;
14
- download: () => Blob | null;
15
- isPlaying: boolean;
18
+ pause: () => Promise<void>;
19
+ resume: () => Promise<void>;
20
+ toggle: () => Promise<void>;
21
+ source: Source | null;
22
+ playbackStatus: PlaybackStatus;
23
+ bufferStatus: BufferStatus;
24
+ isWaiting: boolean;
16
25
  isConnected: boolean;
17
- isStreamed: boolean;
18
- isBuffering: boolean;
19
- chunks: Chunk[];
20
- messages: StreamEventData["message"][];
26
+ metrics: Metrics;
21
27
  }
22
28
  /**
23
29
  * React hook to use the Cartesia audio API.
24
30
  */
25
- declare function useAudio({ apiKey, baseUrl }: UseAudioOptions): UseAudioReturn;
31
+ declare function useTTS({ apiKey, baseUrl, sampleRate, }: UseTTSOptions): UseTTSReturn;
26
32
 
27
- export { type UseAudioOptions, useAudio };
33
+ export { type BufferStatus, type Metrics, type PlaybackStatus, type UseTTSOptions, type UseTTSReturn, useTTS };
@@ -1,27 +1,33 @@
1
- import { C as Chunk, S as StreamEventData } from '../index-DgwnZezj.js';
1
+ import Source from '../tts/source.js';
2
2
  import 'emittery';
3
- import 'partysocket';
4
- import '../lib/client.js';
5
3
  import '../types/index.js';
6
4
 
7
- type UseAudioOptions = {
5
+ type UseTTSOptions = {
8
6
  apiKey: string | null;
9
7
  baseUrl?: string;
8
+ sampleRate: number;
10
9
  };
11
- interface UseAudioReturn {
12
- stream: (options: object) => void;
10
+ type PlaybackStatus = "inactive" | "playing" | "paused" | "finished";
11
+ type BufferStatus = "inactive" | "buffering" | "buffered";
12
+ type Metrics = {
13
+ modelLatency: number | null;
14
+ };
15
+ interface UseTTSReturn {
16
+ buffer: (options: object) => Promise<void>;
13
17
  play: (bufferDuration?: number) => Promise<void>;
14
- download: () => Blob | null;
15
- isPlaying: boolean;
18
+ pause: () => Promise<void>;
19
+ resume: () => Promise<void>;
20
+ toggle: () => Promise<void>;
21
+ source: Source | null;
22
+ playbackStatus: PlaybackStatus;
23
+ bufferStatus: BufferStatus;
24
+ isWaiting: boolean;
16
25
  isConnected: boolean;
17
- isStreamed: boolean;
18
- isBuffering: boolean;
19
- chunks: Chunk[];
20
- messages: StreamEventData["message"][];
26
+ metrics: Metrics;
21
27
  }
22
28
  /**
23
29
  * React hook to use the Cartesia audio API.
24
30
  */
25
- declare function useAudio({ apiKey, baseUrl }: UseAudioOptions): UseAudioReturn;
31
+ declare function useTTS({ apiKey, baseUrl, sampleRate, }: UseTTSOptions): UseTTSReturn;
26
32
 
27
- export { type UseAudioOptions, useAudio };
33
+ export { type BufferStatus, type Metrics, type PlaybackStatus, type UseTTSOptions, type UseTTSReturn, useTTS };
@@ -1,108 +1,144 @@
1
1
  import {
2
- audio_default
3
- } from "../chunk-4MHF74A7.js";
4
- import {
5
- base64ToArray,
6
- bufferToWav
7
- } from "../chunk-5TSWLYOW.js";
8
- import "../chunk-MJIFZWHS.js";
9
- import {
10
- SAMPLE_RATE
11
- } from "../chunk-OVI3W3GG.js";
2
+ Cartesia
3
+ } from "../chunk-T3RG6WV4.js";
4
+ import "../chunk-WVTITUXX.js";
12
5
  import {
13
6
  pingServer
14
- } from "../chunk-XPIMIAAE.js";
7
+ } from "../chunk-3FL2SNIR.js";
8
+ import "../chunk-KWBSQZTY.js";
9
+ import "../chunk-3F5E46FT.js";
10
+ import "../chunk-PQ6CIPFW.js";
11
+ import "../chunk-JGP5BIUV.js";
12
+ import "../chunk-XHTDPLFR.js";
13
+ import {
14
+ Player
15
+ } from "../chunk-36JBKJUN.js";
16
+ import "../chunk-RO7TY474.js";
15
17
  import {
16
18
  __async
17
- } from "../chunk-R4P7LWVZ.js";
19
+ } from "../chunk-WIFMLPT5.js";
18
20
 
19
21
  // src/react/index.ts
20
22
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
21
- function useAudio({ apiKey, baseUrl }) {
23
+ var PING_INTERVAL = 5e3;
24
+ var DEFAULT_BUFFER_DURATION = 0.01;
25
+ function useTTS({
26
+ apiKey,
27
+ baseUrl,
28
+ sampleRate
29
+ }) {
30
+ var _a, _b;
22
31
  if (typeof window === "undefined") {
23
32
  return {
24
- stream: () => {
25
- },
33
+ buffer: () => __async(this, null, function* () {
34
+ }),
26
35
  play: () => __async(this, null, function* () {
27
36
  }),
28
- download: () => null,
37
+ pause: () => __async(this, null, function* () {
38
+ }),
39
+ resume: () => __async(this, null, function* () {
40
+ }),
41
+ toggle: () => __async(this, null, function* () {
42
+ }),
43
+ playbackStatus: "inactive",
44
+ bufferStatus: "inactive",
45
+ isWaiting: false,
46
+ source: null,
29
47
  isConnected: false,
30
- isPlaying: false,
31
- isStreamed: false,
32
- isBuffering: false,
33
- chunks: [],
34
- messages: []
48
+ metrics: {
49
+ modelLatency: null
50
+ }
35
51
  };
36
52
  }
37
- const audio = useMemo(() => {
53
+ const websocket = useMemo(() => {
38
54
  if (!apiKey) {
39
55
  return null;
40
56
  }
41
- const audio2 = new audio_default({ apiKey, baseUrl });
42
- return audio2;
43
- }, [apiKey, baseUrl]);
44
- const streamReturn = useRef(null);
45
- const [isStreamed, setIsStreamed] = useState(false);
46
- const [isPlaying, setIsPlaying] = useState(false);
47
- const [isBuffering, setIsBuffering] = useState(false);
57
+ const cartesia = new Cartesia({ apiKey, baseUrl });
58
+ baseUrl = baseUrl != null ? baseUrl : cartesia.baseUrl;
59
+ return cartesia.tts.websocket({ sampleRate });
60
+ }, [apiKey, baseUrl, sampleRate]);
61
+ const websocketReturn = useRef(null);
62
+ const player = useRef(null);
63
+ const [playbackStatus, setPlaybackStatus] = useState("inactive");
64
+ const [bufferStatus, setBufferStatus] = useState("inactive");
65
+ const [isWaiting, setIsWaiting] = useState(false);
48
66
  const [isConnected, setIsConnected] = useState(false);
49
- const [chunks, setChunks] = useState([]);
67
+ const [bufferDuration, setBufferDuration] = useState(null);
50
68
  const [messages, setMessages] = useState([]);
51
- const latencyEndpoint = "https://api.cartesia.ai";
52
- const stream = useCallback(
69
+ const buffer = useCallback(
53
70
  (options) => __async(this, null, function* () {
54
- var _a;
55
- setIsStreamed(false);
56
- streamReturn.current = (_a = audio == null ? void 0 : audio.stream(options)) != null ? _a : null;
57
- if (!streamReturn.current) {
71
+ var _a2;
72
+ setMessages([]);
73
+ setBufferStatus("buffering");
74
+ websocketReturn.current = (_a2 = websocket == null ? void 0 : websocket.send(options)) != null ? _a2 : null;
75
+ if (!websocketReturn.current) {
58
76
  return;
59
77
  }
60
- setMessages([]);
61
- streamReturn.current.on(
62
- "chunk",
63
- ({ chunks: chunks3 }) => {
64
- setChunks(chunks3);
65
- }
66
- );
67
- streamReturn.current.on(
68
- "message",
69
- (message) => {
70
- setMessages((messages2) => [...messages2, message]);
71
- }
72
- );
73
- const { chunks: chunks2 } = yield streamReturn.current.once("streamed");
74
- setChunks(chunks2);
75
- setIsStreamed(true);
78
+ const unsubscribe = websocketReturn.current.on("message", (message) => {
79
+ setMessages((messages2) => [...messages2, JSON.parse(message)]);
80
+ });
81
+ yield websocketReturn.current.source.once("close");
82
+ setBufferStatus("buffered");
83
+ unsubscribe();
76
84
  }),
77
- [audio]
85
+ [websocket]
78
86
  );
79
- const download = useCallback(() => {
80
- if (!isStreamed) {
81
- return null;
87
+ const metrics = useMemo(() => {
88
+ var _a2;
89
+ if (messages.length === 0) {
90
+ return {
91
+ modelLatency: null
92
+ };
82
93
  }
83
- const audio2 = bufferToWav(SAMPLE_RATE, [base64ToArray(chunks)]);
84
- return new Blob([audio2], { type: "audio/wav" });
85
- }, [isStreamed, chunks]);
94
+ const modelLatency = (_a2 = messages[0].step_time) != null ? _a2 : null;
95
+ return {
96
+ modelLatency: Math.trunc(modelLatency)
97
+ };
98
+ }, [messages]);
86
99
  useEffect(() => {
87
100
  let cleanup = () => {
88
101
  };
89
102
  function setupConnection() {
90
103
  return __async(this, null, function* () {
91
104
  try {
92
- const connection = yield audio == null ? void 0 : audio.connect();
105
+ const connection = yield websocket == null ? void 0 : websocket.connect();
93
106
  if (!connection) {
94
107
  return;
95
108
  }
109
+ const unsubscribes = [];
96
110
  setIsConnected(true);
97
- connection.on("open", () => {
98
- setIsConnected(true);
99
- });
100
- const unsubscribe = connection.on("close", () => {
101
- setIsConnected(false);
102
- });
111
+ unsubscribes.push(
112
+ connection.on("open", () => {
113
+ setIsConnected(true);
114
+ })
115
+ );
116
+ unsubscribes.push(
117
+ connection.on("close", () => {
118
+ setIsConnected(false);
119
+ })
120
+ );
121
+ const intervalId = setInterval(() => {
122
+ if (baseUrl) {
123
+ pingServer(new URL(baseUrl).origin).then((ping) => {
124
+ let bufferDuration2;
125
+ if (ping < 300) {
126
+ bufferDuration2 = 0.01;
127
+ } else if (ping > 1500) {
128
+ bufferDuration2 = 6;
129
+ } else {
130
+ bufferDuration2 = ping / 1e3 * 4;
131
+ }
132
+ setBufferDuration(bufferDuration2);
133
+ });
134
+ }
135
+ }, PING_INTERVAL);
103
136
  return () => {
104
- unsubscribe();
105
- audio == null ? void 0 : audio.disconnect();
137
+ for (const unsubscribe of unsubscribes) {
138
+ unsubscribe();
139
+ }
140
+ clearInterval(intervalId);
141
+ websocket == null ? void 0 : websocket.disconnect();
106
142
  };
107
143
  } catch (e) {
108
144
  console.error(e);
@@ -113,53 +149,69 @@ function useAudio({ apiKey, baseUrl }) {
113
149
  cleanup = cleanupConnection;
114
150
  });
115
151
  return () => cleanup == null ? void 0 : cleanup();
116
- }, [audio]);
152
+ }, [websocket, baseUrl]);
117
153
  const play = useCallback(() => __async(this, null, function* () {
118
- var _a;
119
- if (isPlaying || !streamReturn.current) {
154
+ if (playbackStatus === "playing" || !websocketReturn.current) {
120
155
  return;
121
156
  }
122
- setIsPlaying(true);
123
- const ping = yield pingServer(latencyEndpoint);
124
- let bufferingTimeout;
125
- let bufferDuration;
126
- if (ping < 300) {
127
- bufferDuration = 0;
128
- } else if (ping > 1500) {
129
- bufferDuration = 6;
130
- } else {
131
- bufferDuration = ping / 1e3 * 4;
132
- }
133
- streamReturn.current.once("buffering").then(() => {
134
- bufferingTimeout = setTimeout(() => {
135
- setIsBuffering(true);
136
- }, 250);
157
+ setPlaybackStatus("playing");
158
+ const unsubscribes = [];
159
+ unsubscribes.push(
160
+ websocketReturn.current.source.on("wait", () => {
161
+ setIsWaiting(true);
162
+ })
163
+ );
164
+ unsubscribes.push(
165
+ websocketReturn.current.source.on("read", () => {
166
+ setIsWaiting(false);
167
+ })
168
+ );
169
+ player.current = new Player({
170
+ bufferDuration: bufferDuration != null ? bufferDuration : DEFAULT_BUFFER_DURATION
137
171
  });
138
- streamReturn.current.once("buffered").then(() => {
139
- if (bufferingTimeout) {
140
- clearTimeout(bufferingTimeout);
172
+ yield player.current.play(websocketReturn.current.source);
173
+ for (const unsubscribe of unsubscribes) {
174
+ unsubscribe();
175
+ }
176
+ setPlaybackStatus("finished");
177
+ }), [playbackStatus, bufferDuration]);
178
+ const pause = useCallback(() => __async(this, null, function* () {
179
+ var _a2;
180
+ yield (_a2 = player.current) == null ? void 0 : _a2.pause();
181
+ setPlaybackStatus("paused");
182
+ }), []);
183
+ const resume = useCallback(() => __async(this, null, function* () {
184
+ var _a2;
185
+ yield (_a2 = player.current) == null ? void 0 : _a2.resume();
186
+ setPlaybackStatus("playing");
187
+ }), []);
188
+ const toggle = useCallback(() => __async(this, null, function* () {
189
+ var _a2;
190
+ yield (_a2 = player.current) == null ? void 0 : _a2.toggle();
191
+ setPlaybackStatus((status) => {
192
+ if (status === "playing") {
193
+ return "paused";
141
194
  }
142
- setIsBuffering(false);
143
- });
144
- streamReturn.current.once("scheduled").then((data) => {
145
- setTimeout(() => {
146
- setIsPlaying(false);
147
- }, data.playbackEndsIn);
195
+ if (status === "paused") {
196
+ return "playing";
197
+ }
198
+ return status;
148
199
  });
149
- yield (_a = streamReturn.current) == null ? void 0 : _a.play({ bufferDuration });
150
- }), [isPlaying]);
200
+ }), []);
151
201
  return {
152
- stream,
202
+ buffer,
153
203
  play,
154
- download,
155
- isPlaying,
204
+ pause,
205
+ source: (_b = (_a = websocketReturn.current) == null ? void 0 : _a.source) != null ? _b : null,
206
+ resume,
207
+ toggle,
208
+ playbackStatus,
209
+ bufferStatus,
210
+ isWaiting,
156
211
  isConnected,
157
- isStreamed,
158
- isBuffering,
159
- chunks,
160
- messages
212
+ metrics
161
213
  };
162
214
  }
163
215
  export {
164
- useAudio
216
+ useTTS
165
217
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  pingServer
3
- } from "../chunk-XPIMIAAE.js";
4
- import "../chunk-R4P7LWVZ.js";
3
+ } from "../chunk-3FL2SNIR.js";
4
+ import "../chunk-WIFMLPT5.js";
5
5
  export {
6
6
  pingServer
7
7
  };