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

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 (87) hide show
  1. package/.turbo/turbo-build.log +64 -46
  2. package/CHANGELOG.md +6 -0
  3. package/README.md +123 -16
  4. package/dist/{chunk-XPIMIAAE.js → chunk-3FL2SNIR.js} +1 -1
  5. package/dist/chunk-3GBZUGUD.js +17 -0
  6. package/dist/chunk-4RMSIQLG.js +25 -0
  7. package/dist/chunk-BCQ63627.js +32 -0
  8. package/dist/chunk-JOHSCOLW.js +106 -0
  9. package/dist/chunk-LYPTISWL.js +75 -0
  10. package/dist/chunk-NDNN326Q.js +207 -0
  11. package/dist/chunk-WBK6LLXX.js +58 -0
  12. package/dist/chunk-WE63M7PJ.js +119 -0
  13. package/dist/{chunk-R4P7LWVZ.js → chunk-WIFMLPT5.js} +31 -6
  14. package/dist/chunk-X7SJMF2R.js +22 -0
  15. package/dist/index.cjs +391 -158
  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 +46 -0
  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 +11 -7
  24. package/dist/lib/constants.d.cts +2 -3
  25. package/dist/lib/constants.d.ts +2 -3
  26. package/dist/lib/constants.js +4 -6
  27. package/dist/lib/index.cjs +276 -163
  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 +524 -275
  32. package/dist/react/index.d.cts +20 -14
  33. package/dist/react/index.d.ts +20 -14
  34. package/dist/react/index.js +142 -98
  35. package/dist/react/utils.js +2 -2
  36. package/dist/tts/index.cjs +470 -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 +167 -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 +12 -53
  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/{audio/index.cjs → tts/websocket.cjs} +213 -164
  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 +155 -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 +14 -1
  65. package/src/lib/constants.ts +13 -3
  66. package/src/lib/index.ts +6 -3
  67. package/src/react/index.ts +157 -103
  68. package/src/tts/index.ts +17 -0
  69. package/src/tts/player.ts +109 -0
  70. package/src/tts/source.ts +98 -0
  71. package/src/{audio → tts}/utils.ts +19 -97
  72. package/src/tts/websocket.ts +210 -0
  73. package/src/types/index.ts +63 -0
  74. package/src/voices/index.ts +47 -0
  75. package/dist/audio/index.d.cts +0 -5
  76. package/dist/audio/index.d.ts +0 -5
  77. package/dist/audio/index.js +0 -10
  78. package/dist/audio/utils.d.cts +0 -5
  79. package/dist/audio/utils.d.ts +0 -5
  80. package/dist/chunk-4MHF74A7.js +0 -272
  81. package/dist/chunk-5TSWLYOW.js +0 -113
  82. package/dist/chunk-MJIFZWHS.js +0 -18
  83. package/dist/chunk-OVI3W3GG.js +0 -12
  84. package/dist/chunk-S6A27RQL.js +0 -18
  85. package/dist/index-C2_3XFxn.d.cts +0 -163
  86. package/dist/index-DgwnZezj.d.ts +0 -163
  87. package/src/audio/index.ts +0 -297
@@ -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,95 +1,107 @@
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-X7SJMF2R.js";
4
+ import "../chunk-WBK6LLXX.js";
12
5
  import {
13
6
  pingServer
14
- } from "../chunk-XPIMIAAE.js";
7
+ } from "../chunk-3FL2SNIR.js";
8
+ import "../chunk-4RMSIQLG.js";
9
+ import "../chunk-NDNN326Q.js";
10
+ import "../chunk-JOHSCOLW.js";
11
+ import "../chunk-BCQ63627.js";
12
+ import "../chunk-3GBZUGUD.js";
13
+ import {
14
+ Player
15
+ } from "../chunk-WE63M7PJ.js";
16
+ import "../chunk-LYPTISWL.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
+ websocketReturn.current.on("message", (message) => {
79
+ setMessages((messages2) => [...messages2, JSON.parse(message)]);
80
+ });
81
+ yield websocketReturn.current.source.once("close");
82
+ setBufferStatus("buffered");
76
83
  }),
77
- [audio]
84
+ [websocket]
78
85
  );
79
- const download = useCallback(() => {
80
- if (!isStreamed) {
81
- return null;
86
+ const metrics = useMemo(() => {
87
+ var _a2;
88
+ if (messages.length === 0) {
89
+ return {
90
+ modelLatency: null
91
+ };
82
92
  }
83
- const audio2 = bufferToWav(SAMPLE_RATE, [base64ToArray(chunks)]);
84
- return new Blob([audio2], { type: "audio/wav" });
85
- }, [isStreamed, chunks]);
93
+ const modelLatency = (_a2 = messages[0].step_time) != null ? _a2 : null;
94
+ return {
95
+ modelLatency: Math.trunc(modelLatency)
96
+ };
97
+ }, [messages]);
86
98
  useEffect(() => {
87
99
  let cleanup = () => {
88
100
  };
89
101
  function setupConnection() {
90
102
  return __async(this, null, function* () {
91
103
  try {
92
- const connection = yield audio == null ? void 0 : audio.connect();
104
+ const connection = yield websocket == null ? void 0 : websocket.connect();
93
105
  if (!connection) {
94
106
  return;
95
107
  }
@@ -100,9 +112,25 @@ function useAudio({ apiKey, baseUrl }) {
100
112
  const unsubscribe = connection.on("close", () => {
101
113
  setIsConnected(false);
102
114
  });
115
+ const intervalId = setInterval(() => {
116
+ if (baseUrl) {
117
+ pingServer(new URL(baseUrl).origin).then((ping) => {
118
+ let bufferDuration2;
119
+ if (ping < 300) {
120
+ bufferDuration2 = 0.01;
121
+ } else if (ping > 1500) {
122
+ bufferDuration2 = 6;
123
+ } else {
124
+ bufferDuration2 = ping / 1e3 * 4;
125
+ }
126
+ setBufferDuration(bufferDuration2);
127
+ });
128
+ }
129
+ }, PING_INTERVAL);
103
130
  return () => {
104
131
  unsubscribe();
105
- audio == null ? void 0 : audio.disconnect();
132
+ clearInterval(intervalId);
133
+ websocket == null ? void 0 : websocket.disconnect();
106
134
  };
107
135
  } catch (e) {
108
136
  console.error(e);
@@ -113,53 +141,69 @@ function useAudio({ apiKey, baseUrl }) {
113
141
  cleanup = cleanupConnection;
114
142
  });
115
143
  return () => cleanup == null ? void 0 : cleanup();
116
- }, [audio]);
144
+ }, [websocket, baseUrl]);
117
145
  const play = useCallback(() => __async(this, null, function* () {
118
- var _a;
119
- if (isPlaying || !streamReturn.current) {
146
+ if (playbackStatus === "playing" || !websocketReturn.current) {
120
147
  return;
121
148
  }
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);
149
+ setPlaybackStatus("playing");
150
+ const unsubscribes = [];
151
+ unsubscribes.push(
152
+ websocketReturn.current.source.on("wait", () => {
153
+ setIsWaiting(true);
154
+ })
155
+ );
156
+ unsubscribes.push(
157
+ websocketReturn.current.source.on("read", () => {
158
+ setIsWaiting(false);
159
+ })
160
+ );
161
+ player.current = new Player({
162
+ bufferDuration: bufferDuration != null ? bufferDuration : DEFAULT_BUFFER_DURATION
137
163
  });
138
- streamReturn.current.once("buffered").then(() => {
139
- if (bufferingTimeout) {
140
- clearTimeout(bufferingTimeout);
164
+ yield player.current.play(websocketReturn.current.source);
165
+ for (const unsubscribe of unsubscribes) {
166
+ unsubscribe();
167
+ }
168
+ setPlaybackStatus("finished");
169
+ }), [playbackStatus, bufferDuration]);
170
+ const pause = useCallback(() => __async(this, null, function* () {
171
+ var _a2;
172
+ yield (_a2 = player.current) == null ? void 0 : _a2.pause();
173
+ setPlaybackStatus("paused");
174
+ }), []);
175
+ const resume = useCallback(() => __async(this, null, function* () {
176
+ var _a2;
177
+ yield (_a2 = player.current) == null ? void 0 : _a2.resume();
178
+ setPlaybackStatus("playing");
179
+ }), []);
180
+ const toggle = useCallback(() => __async(this, null, function* () {
181
+ var _a2;
182
+ yield (_a2 = player.current) == null ? void 0 : _a2.toggle();
183
+ setPlaybackStatus((status) => {
184
+ if (status === "playing") {
185
+ return "paused";
141
186
  }
142
- setIsBuffering(false);
143
- });
144
- streamReturn.current.once("scheduled").then((data) => {
145
- setTimeout(() => {
146
- setIsPlaying(false);
147
- }, data.playbackEndsIn);
187
+ if (status === "paused") {
188
+ return "playing";
189
+ }
190
+ return status;
148
191
  });
149
- yield (_a = streamReturn.current) == null ? void 0 : _a.play({ bufferDuration });
150
- }), [isPlaying]);
192
+ }), []);
151
193
  return {
152
- stream,
194
+ buffer,
153
195
  play,
154
- download,
155
- isPlaying,
196
+ pause,
197
+ source: (_b = (_a = websocketReturn.current) == null ? void 0 : _a.source) != null ? _b : null,
198
+ resume,
199
+ toggle,
200
+ playbackStatus,
201
+ bufferStatus,
202
+ isWaiting,
156
203
  isConnected,
157
- isStreamed,
158
- isBuffering,
159
- chunks,
160
- messages
204
+ metrics
161
205
  };
162
206
  }
163
207
  export {
164
- useAudio
208
+ useTTS
165
209
  };
@@ -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
  };