@ai-matrx/media 0.14.0 → 0.15.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/CHANGELOG.md +23 -0
- package/dist/react.cjs +84 -4
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +35 -2
- package/dist/react.d.ts +35 -2
- package/dist/react.js +93 -4
- package/dist/react.js.map +1 -1
- package/dist/speech.cjs +1689 -0
- package/dist/speech.cjs.map +1 -0
- package/dist/speech.d.cts +565 -0
- package/dist/speech.d.ts +565 -0
- package/dist/speech.js +1683 -0
- package/dist/speech.js.map +1 -0
- package/dist/tts-config-JbF86KIt.d.cts +149 -0
- package/dist/tts-config-JbF86KIt.d.ts +149 -0
- package/dist/voices.d.cts +3 -149
- package/dist/voices.d.ts +3 -149
- package/package.json +15 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @ai-matrx/media
|
|
2
2
|
|
|
3
|
+
## 0.15.0 — THE one speech engine (`/speech`) + ReadAloudButton compact size
|
|
4
|
+
|
|
5
|
+
- New `@ai-matrx/media/speech`: `speak()`, the app-wide playback queue (`enqueuePlayback`,
|
|
6
|
+
`pausePlayback`, `resumePlayback`, `skipPlayback`, `playPlaybackItem`, `removePlaybackItem`,
|
|
7
|
+
`clearPlayback`, `subscribePlayback`, …), the playback lock (`claimPlayback` / `releasePlayback`),
|
|
8
|
+
the Cartesia streaming lane (`connectCartesiaTts`, `cartesiaAdapter`, `ProviderSessionError`),
|
|
9
|
+
`SinkAwarePlayer` + output-device routing, and the iOS/WebKit unlock (`primeAudioOutput`,
|
|
10
|
+
`installAudioUnlockListeners`) — moved from matrx-frontend's audio system, which is the reference.
|
|
11
|
+
A host wires it once: `configureSpeech({ getCartesiaToken, resolveVoiceSettings,
|
|
12
|
+
reportProviderFailure?, notifyError?, beforeStart?, describeStartRefusal?, onEngage?, adapters?,
|
|
13
|
+
defaultEngine?, completeRequest?, resolvePronunciations?, invalidateCartesiaToken? })`.
|
|
14
|
+
- `@ai-matrx/media/react`: `useSpeech`, `useReadAloud(text)` (the read-aloud button's whole wiring:
|
|
15
|
+
`status`, `error`, `onPress`), `usePlaybackSnapshot`, `readAloudStatusOf` — over the same queue
|
|
16
|
+
instance (`/react` imports `/speech`, never a bundled copy).
|
|
17
|
+
- New dependency `@cartesia/cartesia-js` ^4.2.0.
|
|
18
|
+
- Consumer action: delete the app's own queue / lock / Cartesia connection / player / unlock and
|
|
19
|
+
import them from `/speech`; call `configureSpeech` once at start-up.
|
|
20
|
+
|
|
21
|
+
- `ReadAloudButton` `size?: "default" | "compact"` (`ReadAloudButtonSize` exported): "compact" is the
|
|
22
|
+
message-footer cell (32px box, 28px pill — the tap system's group geometry) instead of the 38px
|
|
23
|
+
default box. Geometry only; it wins over `variant`.
|
|
24
|
+
- Consumer action: a message footer that drew the old 24px speaker passes `size="compact"`.
|
|
25
|
+
|
|
3
26
|
## 0.14.0 — Read-aloud lives here (speech text, languages, button, language picker)
|
|
4
27
|
|
|
5
28
|
- `@ai-matrx/media/voices`: `parseMarkdownToText` (+ `normalizeSpeechAbbreviations`,
|
package/dist/react.cjs
CHANGED
|
@@ -70,7 +70,11 @@ __export(react_exports, {
|
|
|
70
70
|
VolumeXIcon: () => VolumeXIcon,
|
|
71
71
|
XIcon: () => XIcon,
|
|
72
72
|
cn: () => cn,
|
|
73
|
-
|
|
73
|
+
readAloudStatusOf: () => readAloudStatusOf,
|
|
74
|
+
useMediaDropzone: () => useMediaDropzone,
|
|
75
|
+
usePlaybackSnapshot: () => usePlaybackSnapshot,
|
|
76
|
+
useReadAloud: () => useReadAloud,
|
|
77
|
+
useSpeech: () => useSpeech
|
|
74
78
|
});
|
|
75
79
|
module.exports = __toCommonJS(react_exports);
|
|
76
80
|
|
|
@@ -2542,10 +2546,12 @@ function ReadAloudButton({
|
|
|
2542
2546
|
onPress,
|
|
2543
2547
|
error,
|
|
2544
2548
|
disabled = false,
|
|
2545
|
-
variant,
|
|
2549
|
+
variant: requestedVariant,
|
|
2550
|
+
size = "default",
|
|
2546
2551
|
className,
|
|
2547
2552
|
label = "Read aloud"
|
|
2548
2553
|
}) {
|
|
2554
|
+
const variant = size === "compact" ? "group" : requestedVariant;
|
|
2549
2555
|
if (status === "playing") {
|
|
2550
2556
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_buttons.PauseTapButton, { variant, onClick: onPress, disabled, ariaLabel: "Pause", className });
|
|
2551
2557
|
}
|
|
@@ -2574,10 +2580,84 @@ function ReadAloudButton({
|
|
|
2574
2580
|
);
|
|
2575
2581
|
}
|
|
2576
2582
|
|
|
2583
|
+
// src/react/use-speech.ts
|
|
2584
|
+
var import_react17 = require("react");
|
|
2585
|
+
var import_speech = require("@ai-matrx/media/speech");
|
|
2586
|
+
var cached = (0, import_speech.getPlaybackSnapshot)();
|
|
2587
|
+
function subscribe(onChange) {
|
|
2588
|
+
return (0, import_speech.subscribePlayback)((snapshot) => {
|
|
2589
|
+
cached = snapshot;
|
|
2590
|
+
onChange();
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
var read = () => cached;
|
|
2594
|
+
function usePlaybackSnapshot() {
|
|
2595
|
+
return (0, import_react17.useSyncExternalStore)(subscribe, read, read);
|
|
2596
|
+
}
|
|
2597
|
+
function useSpeech({ adoptText, ...request } = {}) {
|
|
2598
|
+
const { items, currentId } = usePlaybackSnapshot();
|
|
2599
|
+
const [itemId, setItemId] = (0, import_react17.useState)(null);
|
|
2600
|
+
const adoptedId = !itemId && adoptText && currentId ? items.find(
|
|
2601
|
+
(i) => i.id === currentId && i.text === adoptText && (i.status === "playing" || i.status === "paused" || i.status === "loading")
|
|
2602
|
+
)?.id ?? null : null;
|
|
2603
|
+
const effectiveId = itemId ?? adoptedId;
|
|
2604
|
+
const { engine, voice, purpose, processMarkdown = true, label, dictionarySurfaceKey, language, speed } = request;
|
|
2605
|
+
const speak = (0, import_react17.useCallback)(
|
|
2606
|
+
(text) => {
|
|
2607
|
+
const { id } = (0, import_speech.speak)({
|
|
2608
|
+
text,
|
|
2609
|
+
engine,
|
|
2610
|
+
voice,
|
|
2611
|
+
purpose,
|
|
2612
|
+
processMarkdown,
|
|
2613
|
+
label,
|
|
2614
|
+
dictionarySurfaceKey,
|
|
2615
|
+
language,
|
|
2616
|
+
speed
|
|
2617
|
+
});
|
|
2618
|
+
setItemId(id);
|
|
2619
|
+
return id;
|
|
2620
|
+
},
|
|
2621
|
+
[engine, voice, purpose, processMarkdown, label, dictionarySurfaceKey, language, speed]
|
|
2622
|
+
);
|
|
2623
|
+
const item = effectiveId ? items.find((i) => i.id === effectiveId) : void 0;
|
|
2624
|
+
const status = item?.status ?? null;
|
|
2625
|
+
return {
|
|
2626
|
+
speak,
|
|
2627
|
+
status,
|
|
2628
|
+
error: item?.error ?? null,
|
|
2629
|
+
itemId,
|
|
2630
|
+
isMine: effectiveId !== null && effectiveId === currentId,
|
|
2631
|
+
pause: import_speech.pausePlayback,
|
|
2632
|
+
resume: import_speech.resumePlayback,
|
|
2633
|
+
skip: import_speech.skipPlayback,
|
|
2634
|
+
remove: import_speech.removePlaybackItem,
|
|
2635
|
+
playItem: import_speech.playPlaybackItem
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
function readAloudStatusOf(status) {
|
|
2639
|
+
if (status === "playing") return "playing";
|
|
2640
|
+
if (status === "paused") return "paused";
|
|
2641
|
+
if (status === "loading" || status === "queued") return "loading";
|
|
2642
|
+
if (status === "error") return "error";
|
|
2643
|
+
return "idle";
|
|
2644
|
+
}
|
|
2645
|
+
function useReadAloud(text, options = {}) {
|
|
2646
|
+
const { speak, status, error, pause, resume } = useSpeech({ adoptText: text, ...options });
|
|
2647
|
+
const state = readAloudStatusOf(status);
|
|
2648
|
+
const onPress = (0, import_react17.useCallback)(() => {
|
|
2649
|
+
if (state === "loading") return;
|
|
2650
|
+
if (state === "playing") void pause();
|
|
2651
|
+
else if (state === "paused") void resume();
|
|
2652
|
+
else if (text.trim()) speak(text);
|
|
2653
|
+
}, [state, text, speak, pause, resume]);
|
|
2654
|
+
return { status: state, error, onPress, speak };
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2577
2657
|
// src/react/read-aloud-language-picker.tsx
|
|
2578
2658
|
var import_design_system = require("@ai-matrx/design-system");
|
|
2579
2659
|
var import_lucide_react = require("lucide-react");
|
|
2580
|
-
var
|
|
2660
|
+
var import_react18 = require("react");
|
|
2581
2661
|
|
|
2582
2662
|
// src/voices/read-aloud-languages.ts
|
|
2583
2663
|
var READ_ALOUD_LANGUAGES = [
|
|
@@ -2605,7 +2685,7 @@ function readAloudLanguage(code) {
|
|
|
2605
2685
|
// src/react/read-aloud-language-picker.tsx
|
|
2606
2686
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2607
2687
|
function ReadAloudLanguagePicker({ value, onChange, className }) {
|
|
2608
|
-
const [open, setOpen] = (0,
|
|
2688
|
+
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
2609
2689
|
const selected = readAloudLanguage(value);
|
|
2610
2690
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_design_system.Popover, { open, onOpenChange: setOpen, children: [
|
|
2611
2691
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|