@effect-uai/inworld 0.9.0 → 0.11.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/dist/InworldRealtimeSynthesizer.d.mts +6 -13
- package/dist/InworldRealtimeSynthesizer.d.mts.map +1 -1
- package/dist/InworldRealtimeSynthesizer.mjs +1 -1
- package/dist/InworldRealtimeSynthesizer.mjs.map +1 -1
- package/dist/InworldRealtimeTranscriber.d.mts +3 -12
- package/dist/InworldRealtimeTranscriber.d.mts.map +1 -1
- package/dist/InworldRealtimeTranscriber.mjs +1 -1
- package/dist/InworldRealtimeTranscriber.mjs.map +1 -1
- package/dist/InworldSynthesizer.d.mts +4 -8
- package/dist/InworldSynthesizer.d.mts.map +1 -1
- package/dist/InworldSynthesizer.mjs +1 -1
- package/dist/InworldSynthesizer.mjs.map +1 -1
- package/dist/InworldTranscriber.d.mts +3 -7
- package/dist/InworldTranscriber.d.mts.map +1 -1
- package/dist/InworldTranscriber.mjs +1 -1
- package/dist/InworldTranscriber.mjs.map +1 -1
- package/package.json +4 -4
- package/src/InworldRealtimeSynthesizer.ts +1 -1
- package/src/InworldRealtimeTranscriber.ts +1 -1
- package/src/InworldSynthesizer.ts +1 -1
- package/src/InworldTranscriber.ts +1 -1
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService } from "./InworldSynthesizer.mjs";
|
|
2
2
|
import { Effect, Layer, Stream } from "effect";
|
|
3
3
|
import { HttpClient } from "effect/unstable/http";
|
|
4
|
-
import * as _$_effect_uai_core_SpeechSynthesizer0 from "@effect-uai/core/SpeechSynthesizer";
|
|
5
|
-
import { CommonStreamSynthesizeRequest, SpeechSynthesizer, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
|
|
6
|
-
import * as _$_effect_uai_core_AiError0 from "@effect-uai/core/AiError";
|
|
7
|
-
import * as _$_effect_uai_core_Audio0 from "@effect-uai/core/Audio";
|
|
8
4
|
|
|
9
5
|
//#region src/InworldRealtimeSynthesizer.d.ts
|
|
10
6
|
declare namespace InworldRealtimeSynthesizer_d_exports {
|
|
11
7
|
export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, layer, make };
|
|
12
8
|
}
|
|
13
9
|
declare const make: (cfg: Config) => Effect.Effect<{
|
|
14
|
-
synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
streamSynthesisFrom: <E, R>(textIn: Stream.Stream<string, E, R>, request: CommonStreamSynthesizeRequest) => Stream.Stream<_$_effect_uai_core_Audio0.AudioChunk, _$_effect_uai_core_AiError0.AiError | E, R>;
|
|
20
|
-
synthesizeDialogue: (request: _$_effect_uai_core_SpeechSynthesizer0.CommonSynthesizeDialogueRequest) => Effect.Effect<_$_effect_uai_core_Audio0.AudioBlob, _$_effect_uai_core_AiError0.AiError>;
|
|
21
|
-
streamSynthesizeDialogue: (request: _$_effect_uai_core_SpeechSynthesizer0.CommonSynthesizeDialogueRequest) => Stream.Stream<_$_effect_uai_core_Audio0.AudioChunk, _$_effect_uai_core_AiError0.AiError>;
|
|
10
|
+
synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<any, any, never>;
|
|
11
|
+
streamSynthesis: (r: InworldSynthesizeRequest) => Stream.Stream<never, any, never>;
|
|
12
|
+
streamSynthesisFrom: (textIn: any, request: any) => Stream.Stream<AudioChunk, any, unknown>;
|
|
13
|
+
synthesizeDialogue: SpeechSynthesizerService;
|
|
14
|
+
streamSynthesizeDialogue: SpeechSynthesizerService;
|
|
22
15
|
}, never, HttpClient.HttpClient>;
|
|
23
16
|
/**
|
|
24
17
|
* Realtime Layer. Registers `InworldSynthesizer`, the generic
|
|
@@ -27,7 +20,7 @@ declare const make: (cfg: Config) => Effect.Effect<{
|
|
|
27
20
|
* the `Authorization: Basic` header — no `Socket.WebSocketConstructor`
|
|
28
21
|
* needed at the call site.
|
|
29
22
|
*/
|
|
30
|
-
declare const layer: (cfg: Config) => Layer.Layer<
|
|
23
|
+
declare const layer: (cfg: Config) => Layer.Layer<unknown, never, HttpClient.HttpClient>;
|
|
31
24
|
//#endregion
|
|
32
25
|
export { type Config, type InworldSynthesizeRequest, InworldSynthesizer, type InworldSynthesizerService, layer, make, InworldRealtimeSynthesizer_d_exports as t };
|
|
33
26
|
//# sourceMappingURL=InworldRealtimeSynthesizer.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldRealtimeSynthesizer.d.mts","names":[],"sources":["../src/InworldRealtimeSynthesizer.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"InworldRealtimeSynthesizer.d.mts","names":[],"sources":["../src/InworldRealtimeSynthesizer.ts"],"mappings":";;;;;;;;cAsCa,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAM,MAAA,CAAA,MAAA;;;;;;;;;;;;;;cAuBnB,KAAA,GAAS,GAAA,EAAK,MAAA,KAAM,KAAA,CAAA,KAAA,iBAAA,UAAA,CAAA,UAAA"}
|
|
@@ -20,7 +20,7 @@ var InworldRealtimeSynthesizer_exports = /* @__PURE__ */ __exportAll({
|
|
|
20
20
|
layer: () => layer,
|
|
21
21
|
make: () => make
|
|
22
22
|
});
|
|
23
|
-
const make = (cfg) => Effect.map(HttpClient.HttpClient
|
|
23
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient, (client) => ({
|
|
24
24
|
synthesize: (r) => synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
25
25
|
streamSynthesis: (r) => streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),
|
|
26
26
|
streamSynthesisFrom: (textIn, request) => streamSynthesis(cfg)(textIn, request),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldRealtimeSynthesizer.mjs","names":["realtimeStream"],"sources":["../src/InworldRealtimeSynthesizer.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldSynthesizer`. Wires `streamSynthesisFrom` to\n * `wss://api.inworld.ai/tts/v1/voice:streamBidirectional` and registers\n * the `TtsIncrementalText` capability marker, so the call compiles\n * against this Layer alone.\n *\n * Sync `synthesize` and chunked `streamSynthesis` reuse the implementations\n * exported from `./InworldSynthesizer.js` — the only added surface here is\n * the WS path.\n */\nimport { Effect, Layer, Stream } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n type Config,\n dialogueUnsupportedImpl,\n InworldSynthesizer,\n type InworldSynthesizerService,\n type InworldSynthesizeRequest,\n streamDialogueUnsupportedImpl,\n streamSynthesisImpl,\n synthesizeImpl,\n} from \"./InworldSynthesizer.js\"\nimport { streamSynthesis as realtimeStream } from \"./realtimeTts.js\"\n\nexport type {\n Config,\n InworldSynthesizerService,\n InworldSynthesizeRequest,\n} from \"./InworldSynthesizer.js\"\nexport { InworldSynthesizer } from \"./InworldSynthesizer.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient
|
|
1
|
+
{"version":3,"file":"InworldRealtimeSynthesizer.mjs","names":["realtimeStream"],"sources":["../src/InworldRealtimeSynthesizer.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldSynthesizer`. Wires `streamSynthesisFrom` to\n * `wss://api.inworld.ai/tts/v1/voice:streamBidirectional` and registers\n * the `TtsIncrementalText` capability marker, so the call compiles\n * against this Layer alone.\n *\n * Sync `synthesize` and chunked `streamSynthesis` reuse the implementations\n * exported from `./InworldSynthesizer.js` — the only added surface here is\n * the WS path.\n */\nimport { Effect, Layer, Stream } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n type Config,\n dialogueUnsupportedImpl,\n InworldSynthesizer,\n type InworldSynthesizerService,\n type InworldSynthesizeRequest,\n streamDialogueUnsupportedImpl,\n streamSynthesisImpl,\n synthesizeImpl,\n} from \"./InworldSynthesizer.js\"\nimport { streamSynthesis as realtimeStream } from \"./realtimeTts.js\"\n\nexport type {\n Config,\n InworldSynthesizerService,\n InworldSynthesizeRequest,\n} from \"./InworldSynthesizer.js\"\nexport { InworldSynthesizer } from \"./InworldSynthesizer.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient,\n (client) =>\n ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: (textIn, request) =>\n realtimeStream(cfg)(textIn, request as InworldSynthesizeRequest),\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }) satisfies InworldSynthesizerService,\n )\n\n/**\n * Realtime Layer. Registers `InworldSynthesizer`, the generic\n * `SpeechSynthesizer`, **and** the `TtsIncrementalText` capability\n * marker. The WS constructor uses the `ws` peer dep internally to set\n * the `Authorization: Basic` header — no `Socket.WebSocketConstructor`\n * needed at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(\n make(cfg),\n (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>\n s.streamSynthesisFrom(textIn, req),\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n }),\n ),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,aACV,YACE;CACC,aAAa,MACX,eAAe,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACnF,kBAAkB,MAChB,oBAAoB,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACxF,sBAAsB,QAAQ,YAC5BA,gBAAe,IAAI,CAAC,QAAQ,QAAoC;CAClE,oBAAoB;CACpB,0BAA0B;CAC3B,EACJ;;;;;;;;AASH,MAAa,SAAS,QACpB,MAAM,SACJ,MAAM,OAAO,oBAAoB,KAAK,IAAI,CAAC,EAC3C,MAAM,OACJ,mBACA,OAAO,IACL,KAAK,IAAI,GACR,OAAiC;CAChC,aAAa,QACX,EAAE,WAAW,IAAgC;CAC/C,kBAAkB,QAChB,EAAE,gBAAgB,IAAgC;CACpD,sBAAsB,QAAQ,QAC5B,EAAE,oBAAoB,QAAQ,IAAI;CACpC,oBAAoB,EAAE;CACtB,0BAA0B,EAAE;CAC7B,EACF,CACF,EACD,MAAM,QAAQ,oBAAoB,KAAA,EAAU,CAC7C"}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService } from "./InworldTranscriber.mjs";
|
|
2
2
|
import { Effect, Layer } from "effect";
|
|
3
3
|
import { HttpClient } from "effect/unstable/http";
|
|
4
|
-
import * as _$_effect_uai_core_AiError0 from "@effect-uai/core/AiError";
|
|
5
|
-
import * as _$_effect_uai_core_Transcriber0 from "@effect-uai/core/Transcriber";
|
|
6
|
-
import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
|
|
7
|
-
import * as _$effect_Schema0 from "effect/Schema";
|
|
8
|
-
import * as _$_effect_uai_core_Transcript0 from "@effect-uai/core/Transcript";
|
|
9
4
|
import * as _$effect_Stream0 from "effect/Stream";
|
|
10
5
|
|
|
11
6
|
//#region src/InworldRealtimeTranscriber.d.ts
|
|
@@ -13,18 +8,14 @@ declare namespace InworldRealtimeTranscriber_d_exports {
|
|
|
13
8
|
export { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService, layer, make };
|
|
14
9
|
}
|
|
15
10
|
declare const make: (cfg: Config) => Effect.Effect<{
|
|
16
|
-
transcribe: (r: InworldTranscribeRequest) => Effect.Effect<
|
|
17
|
-
|
|
18
|
-
words?: _$_effect_uai_core_Transcript0.WordTimestamp[];
|
|
19
|
-
text: string;
|
|
20
|
-
}, _$_effect_uai_core_AiError0.AiError, never>;
|
|
21
|
-
streamTranscriptionFrom: <E, R>(audioIn: _$effect_Stream0.Stream<Uint8Array<ArrayBufferLike>, E, R>, request: _$_effect_uai_core_Transcriber0.CommonStreamTranscribeRequest) => _$effect_Stream0.Stream<_$_effect_uai_core_Transcript0.TranscriptEvent, _$_effect_uai_core_AiError0.AiError | E, R>;
|
|
11
|
+
transcribe: (r: InworldTranscribeRequest) => Effect.Effect<any, any, unknown>;
|
|
12
|
+
streamTranscriptionFrom: (audioIn: any, request: any) => _$effect_Stream0.Stream<TranscriptEvent, any, unknown>;
|
|
22
13
|
}, never, HttpClient.HttpClient>;
|
|
23
14
|
/**
|
|
24
15
|
* Realtime Layer. Registers `InworldTranscriber`, the generic
|
|
25
16
|
* `Transcriber`, **and** the `SttStreaming` capability marker.
|
|
26
17
|
*/
|
|
27
|
-
declare const layer: (cfg: Config) => Layer.Layer<
|
|
18
|
+
declare const layer: (cfg: Config) => Layer.Layer<unknown, never, HttpClient.HttpClient>;
|
|
28
19
|
//#endregion
|
|
29
20
|
export { type Config, type InworldTranscribeRequest, InworldTranscriber, type InworldTranscriberService, layer, make, InworldRealtimeTranscriber_d_exports as t };
|
|
30
21
|
//# sourceMappingURL=InworldRealtimeTranscriber.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldRealtimeTranscriber.d.mts","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"InworldRealtimeTranscriber.d.mts","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"mappings":";;;;;;;;;cAiCa,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAM,MAAA,CAAA,MAAA;;;;;;;;cAenB,KAAA,GAAS,GAAA,EAAK,MAAA,KAAM,KAAA,CAAA,KAAA,iBAAA,UAAA,CAAA,UAAA"}
|
|
@@ -19,7 +19,7 @@ var InworldRealtimeTranscriber_exports = /* @__PURE__ */ __exportAll({
|
|
|
19
19
|
layer: () => layer,
|
|
20
20
|
make: () => make
|
|
21
21
|
});
|
|
22
|
-
const make = (cfg) => Effect.map(HttpClient.HttpClient
|
|
22
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient, (client) => ({
|
|
23
23
|
transcribe: (r) => transcribeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
24
24
|
streamTranscriptionFrom: (audioIn, request) => streamTranscription(cfg)(audioIn, request)
|
|
25
25
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldRealtimeTranscriber.mjs","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldTranscriber`. Wires `streamTranscriptionFrom`\n * to `wss://api.inworld.ai/stt/v1/transcribe:streamBidirectional` and\n * registers the `SttStreaming` capability marker, so calls compile against\n * this Layer alone.\n *\n * Sync `transcribe` reuses `transcribeImpl` from `./InworldTranscriber.js` —\n * the only added surface is the WS path.\n */\nimport { Effect, Layer } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonTranscribeRequest,\n SttStreaming,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport {\n type Config,\n InworldTranscriber,\n type InworldTranscriberService,\n type InworldTranscribeRequest,\n transcribeImpl,\n} from \"./InworldTranscriber.js\"\nimport { streamTranscription } from \"./realtimeStt.js\"\n\nexport type {\n Config,\n InworldTranscriberService,\n InworldTranscribeRequest,\n} from \"./InworldTranscriber.js\"\nexport { InworldTranscriber } from \"./InworldTranscriber.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient
|
|
1
|
+
{"version":3,"file":"InworldRealtimeTranscriber.mjs","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldTranscriber`. Wires `streamTranscriptionFrom`\n * to `wss://api.inworld.ai/stt/v1/transcribe:streamBidirectional` and\n * registers the `SttStreaming` capability marker, so calls compile against\n * this Layer alone.\n *\n * Sync `transcribe` reuses `transcribeImpl` from `./InworldTranscriber.js` —\n * the only added surface is the WS path.\n */\nimport { Effect, Layer } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonTranscribeRequest,\n SttStreaming,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport {\n type Config,\n InworldTranscriber,\n type InworldTranscriberService,\n type InworldTranscribeRequest,\n transcribeImpl,\n} from \"./InworldTranscriber.js\"\nimport { streamTranscription } from \"./realtimeStt.js\"\n\nexport type {\n Config,\n InworldTranscriberService,\n InworldTranscribeRequest,\n} from \"./InworldTranscriber.js\"\nexport { InworldTranscriber } from \"./InworldTranscriber.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient,\n (client) =>\n ({\n transcribe: (r) =>\n transcribeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: (audioIn, request) => streamTranscription(cfg)(audioIn, request),\n }) satisfies InworldTranscriberService,\n )\n\n/**\n * Realtime Layer. Registers `InworldTranscriber`, the generic\n * `Transcriber`, **and** the `SttStreaming` capability marker.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(\n make(cfg),\n (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n }),\n ),\n ),\n Layer.succeed(SttStreaming, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,aACV,YACE;CACC,aAAa,MACX,eAAe,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACnF,0BAA0B,SAAS,YAAY,oBAAoB,IAAI,CAAC,SAAS,QAAQ;CAC1F,EACJ;;;;;AAMH,MAAa,SAAS,QACpB,MAAM,SACJ,MAAM,OAAO,oBAAoB,KAAK,IAAI,CAAC,EAC3C,MAAM,OACJ,aACA,OAAO,IACL,KAAK,IAAI,GACR,OAA2B;CAC1B,aAAa,QACX,EAAE,WAAW,IAAgC;CAC/C,yBAAyB,EAAE;CAC5B,EACF,CACF,EACD,MAAM,QAAQ,cAAc,KAAA,EAAU,CACvC"}
|
|
@@ -4,7 +4,6 @@ import { Context, Effect, Layer, Redacted, Stream } from "effect";
|
|
|
4
4
|
import { HttpClient } from "effect/unstable/http";
|
|
5
5
|
import { CommonSynthesizeRequest, SpeechSynthesizer, SpeechSynthesizerService } from "@effect-uai/core/SpeechSynthesizer";
|
|
6
6
|
import * as AiError from "@effect-uai/core/AiError";
|
|
7
|
-
import * as _$_effect_uai_core_Audio0 from "@effect-uai/core/Audio";
|
|
8
7
|
import { AudioBlob, AudioChunk } from "@effect-uai/core/Audio";
|
|
9
8
|
|
|
10
9
|
//#region src/InworldSynthesizer.d.ts
|
|
@@ -46,21 +45,18 @@ declare const buildBody: (r: InworldSynthesizeRequest) => Effect.Effect<{
|
|
|
46
45
|
applyTextNormalization?: "ON" | "OFF";
|
|
47
46
|
temperature?: number;
|
|
48
47
|
deliveryMode?: InworldDeliveryMode;
|
|
49
|
-
language?:
|
|
48
|
+
language?: any;
|
|
50
49
|
text: string;
|
|
51
50
|
voiceId: string;
|
|
52
51
|
modelId: InworldTtsModel;
|
|
53
52
|
audioConfig: AudioConfig;
|
|
54
53
|
};
|
|
55
|
-
format:
|
|
54
|
+
format: any;
|
|
56
55
|
}, AiError.AiError, never>;
|
|
57
56
|
/** Exported for reuse by `InworldRealtimeSynthesizer`. */
|
|
58
|
-
declare const synthesizeImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Effect.Effect<
|
|
59
|
-
format: _$_effect_uai_core_Audio0.AudioFormat;
|
|
60
|
-
bytes: Uint8Array<ArrayBufferLike>;
|
|
61
|
-
}, AiError.AiError, HttpClient.HttpClient>;
|
|
57
|
+
declare const synthesizeImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Effect.Effect<any, any, HttpClient.HttpClient>;
|
|
62
58
|
/** Exported for reuse by `InworldRealtimeSynthesizer`. */
|
|
63
|
-
declare const streamSynthesisImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Stream.Stream<
|
|
59
|
+
declare const streamSynthesisImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Stream.Stream<never, any, HttpClient.HttpClient>;
|
|
64
60
|
/** Exported for reuse by `InworldRealtimeSynthesizer`. */
|
|
65
61
|
declare const dialogueUnsupportedImpl: SpeechSynthesizerService["synthesizeDialogue"];
|
|
66
62
|
/** Exported for reuse by `InworldRealtimeSynthesizer`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldSynthesizer.d.mts","names":[],"sources":["../src/InworldSynthesizer.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"InworldSynthesizer.d.mts","names":[],"sources":["../src/InworldSynthesizer.ts"],"mappings":";;;;;;;;;;;;;;;;;AA+CA;;;;KAAY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,eAAA;EAAA,SACP,OAAA,EAAS,cAAA;EAAA,SACT,WAAA;EAAA,SACA,YAAA,GAAe,mBAAA;EAAA,SACf,sBAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GAAa,CAAA,EAAG,wBAAA,KAA6B,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,OAAA;EAAA,SAC9E,eAAA,GACP,CAAA,EAAG,wBAAA,KACA,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,OAAA;EAAA,SAC9B,mBAAA,EAAqB,wBAAA;EAAA,SACrB,kBAAA,EAAoB,wBAAA;EAAA,SACpB,wBAAA,EAA0B,wBAAA;AAAA;AAAA,cACpC,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;cAyBvD,SAAA,GAAa,CAAA,EAAG,wBAAA,KAAwB,MAAA,CAAA,MAAA;;;;;;;;;;;;;;cA4CxC,cAAA,GAAkB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA,WAAA,UAAA,CAAA,UAAA;;cAoCpE,mBAAA,GAAuB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA,aAAA,UAAA,CAAA,UAAA;;cA2CzE,uBAAA,EAAyB,wBAAA;;cAUzB,6BAAA,EAA+B,wBAAA;AAAA,cAc/B,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;;;;cAgBjD,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,iBAAA,SAA0B,UAAA,CAAW,UAAA"}
|
|
@@ -135,7 +135,7 @@ const streamDialogueUnsupportedImpl = () => Stream.fail(new AiError.Unsupported(
|
|
|
135
135
|
capability: "streamSynthesizeDialogue",
|
|
136
136
|
reason: "Inworld TTS has no multi-speaker endpoint."
|
|
137
137
|
}));
|
|
138
|
-
const make = (cfg) => Effect.map(HttpClient.HttpClient
|
|
138
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient, (client) => ({
|
|
139
139
|
synthesize: (r) => synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
140
140
|
streamSynthesis: (r) => streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),
|
|
141
141
|
streamSynthesisFrom: streamUnsupported,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldSynthesizer.mjs","names":["Arr"],"sources":["../src/InworldSynthesizer.ts"],"sourcesContent":["/**\n * Sync + chunked-HTTP TTS via Inworld's REST endpoints.\n *\n * - `synthesize` → `POST /tts/v1/voice` (JSON body, single base64 audio in\n * response).\n * - `streamSynthesis` → `POST /tts/v1/voice:stream` (NDJSON response, one\n * JSON object per line, each carrying a base64 audio chunk).\n *\n * Incremental text-in (`streamSynthesisFrom`) lives at the\n * `InworldRealtimeSynthesizer` subpath, which adds the WS path and the\n * `TtsIncrementalText` capability marker.\n */\nimport { Array as Arr, Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk } from \"@effect-uai/core/Audio\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n type CustomPronunciation,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n audioConfigFor,\n authHeader,\n decodeAudioContent,\n defaultFormat,\n httpStatusError,\n transportFailure,\n} from \"./codec.js\"\nimport type { InworldDeliveryMode, InworldTtsModel, InworldVoiceId } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed synthesize request.\n *\n * - `deliveryMode` only honored by `inworld-tts-2` (`STABLE` / `BALANCED` /\n * `CREATIVE` — older models ignore it).\n * - `temperature` valid range is `(0, 2]` per docs.\n * - `applyTextNormalization` defaults to `ON`; pass `\"OFF\"` to feed the\n * model raw text (faster, but punctuation pacing is on you).\n */\nexport type InworldSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\" | \"voiceId\"> & {\n readonly model: InworldTtsModel\n readonly voiceId: InworldVoiceId\n readonly temperature?: number\n readonly deliveryMode?: InworldDeliveryMode\n readonly applyTextNormalization?: \"ON\" | \"OFF\"\n}\n\nexport type InworldSynthesizerService = {\n readonly synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n r: InworldSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: SpeechSynthesizerService[\"streamSynthesisFrom\"]\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class InworldSynthesizer extends Context.Service<\n InworldSynthesizer,\n InworldSynthesizerService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldSynthesizer\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld accepts inline phoneme overrides as `/ipa/` tokens directly\n * in the text, no separate field. `CustomPronunciation.pronunciation`\n * is always IPA, so every entry is inlined. Whole-word,\n * case-insensitive replacement.\n */\nconst escapeForRegex = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\nconst applyPronunciations = (\n text: string,\n pronunciations: ReadonlyArray<CustomPronunciation> | undefined,\n): string => {\n if (pronunciations === undefined) return text\n return Arr.reduce(pronunciations, text, (acc, p) =>\n acc.replace(new RegExp(`\\\\b${escapeForRegex(p.phrase)}\\\\b`, \"i\"), `/${p.pronunciation}/`),\n )\n}\n\n/** Exported for reuse by the realtime variant's BOS `create` frame. */\nexport const buildBody = (r: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const audioConfig = yield* audioConfigFor(format, r.speed)\n const body = {\n text: applyPronunciations(r.text, r.pronunciations),\n voiceId: r.voiceId,\n modelId: r.model,\n audioConfig,\n ...(r.languageCode !== undefined && { language: r.languageCode }),\n ...(r.deliveryMode !== undefined && { deliveryMode: r.deliveryMode }),\n ...(r.temperature !== undefined && { temperature: r.temperature }),\n ...(r.applyTextNormalization !== undefined && {\n applyTextNormalization: r.applyTextNormalization,\n }),\n }\n return { body, format }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schemas\n// ---------------------------------------------------------------------------\n\nconst SyncResponse = Schema.Struct({ audioContent: Schema.String })\nconst decodeSyncResponse = Schema.decodeUnknownEffect(SyncResponse)\n\nconst StreamLine = Schema.Struct({\n result: Schema.optional(Schema.Struct({ audioContent: Schema.optional(Schema.String) })),\n error: Schema.optional(Schema.Unknown),\n})\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\nconst buildRequest = (cfg: Config, path: \"/tts/v1/voice\" | \"/tts/v1/voice:stream\", body: unknown) =>\n HttpClientRequest.post(`${baseUrl(cfg)}${path}`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const synthesizeImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body, format } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeSyncResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"sync TTS response missing `audioContent`\", cause, json },\n }),\n ),\n )\n const bytes = yield* decodeAudioContent(wire.audioContent)\n return { format, bytes } satisfies AudioBlob\n })\n\nconst lineToStream = (line: typeof StreamLine.Type): Stream.Stream<AudioChunk, AiError.AiError> => {\n if (line.error !== undefined) {\n return Stream.fail(new AiError.GenerationFailed({ provider: \"inworld\", raw: line.error }))\n }\n const b64 = line.result?.audioContent\n if (b64 === undefined) return Stream.empty\n return Stream.fromEffect(\n decodeAudioContent(b64).pipe(Effect.map((bytes): AudioChunk => ({ bytes }))),\n )\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamSynthesisImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice:stream\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n JSONL.fromBytes,\n JSONL.parse(StreamLine),\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"NDJSON parse failed\", cause },\n }),\n ),\n Stream.flatMap(lineToStream),\n )\n }),\n )\n\nconst streamUnsupported = <E, R>(\n _textIn: Stream.Stream<string, E, R>,\n _request: CommonStreamSynthesizeRequest,\n): Stream.Stream<AudioChunk, AiError.AiError | E, R> => {\n const fail: Stream.Stream<AudioChunk, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesisFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeSynthesizer` to use the WS streamSynthesisFrom path.\",\n }),\n )\n return fail\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const dialogueUnsupportedImpl: SpeechSynthesizerService[\"synthesizeDialogue\"] = () =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"synthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamDialogueUnsupportedImpl: SpeechSynthesizerService[\"streamSynthesizeDialogue\"] =\n () =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldSynthesizerService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient.asEffect(), (client) => ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: streamUnsupported,\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldSynthesizer` + the generic\n * `SpeechSynthesizer`. Does **not** register `TtsIncrementalText` — for\n * incremental text-in use `@effect-uai/inworld/InworldRealtimeSynthesizer`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldSynthesizer | SpeechSynthesizer, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(\n make(cfg),\n (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: s.streamSynthesisFrom,\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n }),\n ),\n ),\n )\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InworldSynthesizer.mjs","names":["Arr"],"sources":["../src/InworldSynthesizer.ts"],"sourcesContent":["/**\n * Sync + chunked-HTTP TTS via Inworld's REST endpoints.\n *\n * - `synthesize` → `POST /tts/v1/voice` (JSON body, single base64 audio in\n * response).\n * - `streamSynthesis` → `POST /tts/v1/voice:stream` (NDJSON response, one\n * JSON object per line, each carrying a base64 audio chunk).\n *\n * Incremental text-in (`streamSynthesisFrom`) lives at the\n * `InworldRealtimeSynthesizer` subpath, which adds the WS path and the\n * `TtsIncrementalText` capability marker.\n */\nimport { Array as Arr, Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk } from \"@effect-uai/core/Audio\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n type CustomPronunciation,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n audioConfigFor,\n authHeader,\n decodeAudioContent,\n defaultFormat,\n httpStatusError,\n transportFailure,\n} from \"./codec.js\"\nimport type { InworldDeliveryMode, InworldTtsModel, InworldVoiceId } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed synthesize request.\n *\n * - `deliveryMode` only honored by `inworld-tts-2` (`STABLE` / `BALANCED` /\n * `CREATIVE` — older models ignore it).\n * - `temperature` valid range is `(0, 2]` per docs.\n * - `applyTextNormalization` defaults to `ON`; pass `\"OFF\"` to feed the\n * model raw text (faster, but punctuation pacing is on you).\n */\nexport type InworldSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\" | \"voiceId\"> & {\n readonly model: InworldTtsModel\n readonly voiceId: InworldVoiceId\n readonly temperature?: number\n readonly deliveryMode?: InworldDeliveryMode\n readonly applyTextNormalization?: \"ON\" | \"OFF\"\n}\n\nexport type InworldSynthesizerService = {\n readonly synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n r: InworldSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: SpeechSynthesizerService[\"streamSynthesisFrom\"]\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class InworldSynthesizer extends Context.Service<\n InworldSynthesizer,\n InworldSynthesizerService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldSynthesizer\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld accepts inline phoneme overrides as `/ipa/` tokens directly\n * in the text, no separate field. `CustomPronunciation.pronunciation`\n * is always IPA, so every entry is inlined. Whole-word,\n * case-insensitive replacement.\n */\nconst escapeForRegex = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\nconst applyPronunciations = (\n text: string,\n pronunciations: ReadonlyArray<CustomPronunciation> | undefined,\n): string => {\n if (pronunciations === undefined) return text\n return Arr.reduce(pronunciations, text, (acc, p) =>\n acc.replace(new RegExp(`\\\\b${escapeForRegex(p.phrase)}\\\\b`, \"i\"), `/${p.pronunciation}/`),\n )\n}\n\n/** Exported for reuse by the realtime variant's BOS `create` frame. */\nexport const buildBody = (r: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const audioConfig = yield* audioConfigFor(format, r.speed)\n const body = {\n text: applyPronunciations(r.text, r.pronunciations),\n voiceId: r.voiceId,\n modelId: r.model,\n audioConfig,\n ...(r.languageCode !== undefined && { language: r.languageCode }),\n ...(r.deliveryMode !== undefined && { deliveryMode: r.deliveryMode }),\n ...(r.temperature !== undefined && { temperature: r.temperature }),\n ...(r.applyTextNormalization !== undefined && {\n applyTextNormalization: r.applyTextNormalization,\n }),\n }\n return { body, format }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schemas\n// ---------------------------------------------------------------------------\n\nconst SyncResponse = Schema.Struct({ audioContent: Schema.String })\nconst decodeSyncResponse = Schema.decodeUnknownEffect(SyncResponse)\n\nconst StreamLine = Schema.Struct({\n result: Schema.optional(Schema.Struct({ audioContent: Schema.optional(Schema.String) })),\n error: Schema.optional(Schema.Unknown),\n})\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\nconst buildRequest = (cfg: Config, path: \"/tts/v1/voice\" | \"/tts/v1/voice:stream\", body: unknown) =>\n HttpClientRequest.post(`${baseUrl(cfg)}${path}`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const synthesizeImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body, format } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeSyncResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"sync TTS response missing `audioContent`\", cause, json },\n }),\n ),\n )\n const bytes = yield* decodeAudioContent(wire.audioContent)\n return { format, bytes } satisfies AudioBlob\n })\n\nconst lineToStream = (line: typeof StreamLine.Type): Stream.Stream<AudioChunk, AiError.AiError> => {\n if (line.error !== undefined) {\n return Stream.fail(new AiError.GenerationFailed({ provider: \"inworld\", raw: line.error }))\n }\n const b64 = line.result?.audioContent\n if (b64 === undefined) return Stream.empty\n return Stream.fromEffect(\n decodeAudioContent(b64).pipe(Effect.map((bytes): AudioChunk => ({ bytes }))),\n )\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamSynthesisImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice:stream\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n JSONL.fromBytes,\n JSONL.parse(StreamLine),\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"NDJSON parse failed\", cause },\n }),\n ),\n Stream.flatMap(lineToStream),\n )\n }),\n )\n\nconst streamUnsupported = <E, R>(\n _textIn: Stream.Stream<string, E, R>,\n _request: CommonStreamSynthesizeRequest,\n): Stream.Stream<AudioChunk, AiError.AiError | E, R> => {\n const fail: Stream.Stream<AudioChunk, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesisFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeSynthesizer` to use the WS streamSynthesisFrom path.\",\n }),\n )\n return fail\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const dialogueUnsupportedImpl: SpeechSynthesizerService[\"synthesizeDialogue\"] = () =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"synthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamDialogueUnsupportedImpl: SpeechSynthesizerService[\"streamSynthesizeDialogue\"] =\n () =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldSynthesizerService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: streamUnsupported,\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldSynthesizer` + the generic\n * `SpeechSynthesizer`. Does **not** register `TtsIncrementalText` — for\n * incremental text-in use `@effect-uai/inworld/InworldRealtimeSynthesizer`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldSynthesizer | SpeechSynthesizer, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(\n make(cfg),\n (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: s.streamSynthesisFrom,\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n }),\n ),\n ),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,IAAa,qBAAb,cAAwC,QAAQ,SAG7C,CAAC,4DAA4D,CAAC;;;;;;;AAcjE,MAAM,kBAAkB,MAAsB,EAAE,QAAQ,uBAAuB,OAAO;AAEtF,MAAM,uBACJ,MACA,mBACW;AACX,KAAI,mBAAmB,KAAA,EAAW,QAAO;AACzC,QAAOA,MAAI,OAAO,gBAAgB,OAAO,KAAK,MAC5C,IAAI,QAAQ,IAAI,OAAO,MAAM,eAAe,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,cAAc,GAAG,CAC1F;;;AAIH,MAAa,aAAa,MACxB,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,EAAE,gBAAgB;CACjC,MAAM,cAAc,OAAO,eAAe,QAAQ,EAAE,MAAM;AAa1D,QAAO;EAAE,MAAA;GAXP,MAAM,oBAAoB,EAAE,MAAM,EAAE,eAAe;GACnD,SAAS,EAAE;GACX,SAAS,EAAE;GACX;GACA,GAAI,EAAE,iBAAiB,KAAA,KAAa,EAAE,UAAU,EAAE,cAAc;GAChE,GAAI,EAAE,iBAAiB,KAAA,KAAa,EAAE,cAAc,EAAE,cAAc;GACpE,GAAI,EAAE,gBAAgB,KAAA,KAAa,EAAE,aAAa,EAAE,aAAa;GACjE,GAAI,EAAE,2BAA2B,KAAA,KAAa,EAC5C,wBAAwB,EAAE,wBAC3B;GAEU;EAAE;EAAQ;EACvB;AAMJ,MAAM,eAAe,OAAO,OAAO,EAAE,cAAc,OAAO,QAAQ,CAAC;AACnE,MAAM,qBAAqB,OAAO,oBAAoB,aAAa;AAEnE,MAAM,aAAa,OAAO,OAAO;CAC/B,QAAQ,OAAO,SAAS,OAAO,OAAO,EAAE,cAAc,OAAO,SAAS,OAAO,OAAO,EAAE,CAAC,CAAC;CACxF,OAAO,OAAO,SAAS,OAAO,QAAQ;CACvC,CAAC;AAMF,MAAM,WAAW,QAAgB,IAAI,WAAW;AAEhD,MAAM,gBAAgB,KAAa,MAAgD,SACjF,kBAAkB,KAAK,GAAG,QAAQ,IAAI,GAAG,OAAO,CAAC,KAC/C,kBAAkB,UAAU,iBAAiB,WAAW,IAAI,OAAO,CAAC,EACpE,kBAAkB,eAAe,KAAK,CACvC;;AAGH,MAAa,kBAAkB,SAAiB,YAC9C,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,EAAE,MAAM,WAAW,OAAO,UAAU,QAAQ;CAClD,MAAM,cAAc,aAAa,KAAK,iBAAiB,KAAK;CAC5D,MAAM,WAAW,OAAO,OAAO,QAAQ,YAAY,CAAC,KAAK,OAAO,SAAS,iBAAiB,CAAC;AAC3F,KAAI,SAAS,UAAU,KAAK;EAC1B,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,oBAAoB,GAAG,CAAC;AACtE,SAAO,OAAO,OAAO,KAAK,gBAAgB,SAAS,QAAQ,KAAK,CAAC;;CAEnE,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,iBAAiB,CAAC;AAWzE,QAAO;EAAE;EAAQ,OAAA,OADI,oBAAmB,OATpB,mBAAmB,KAAK,CAAC,KAC3C,OAAO,UACJ,UACC,IAAI,QAAQ,iBAAiB;GAC3B,UAAU;GACV,KAAK;IAAE,SAAS;IAA4C;IAAO;IAAM;GAC1E,CAAC,CACL,CACF,EAC4C,aAAa;EAClC;EACxB;AAEJ,MAAM,gBAAgB,SAA6E;AACjG,KAAI,KAAK,UAAU,KAAA,EACjB,QAAO,OAAO,KAAK,IAAI,QAAQ,iBAAiB;EAAE,UAAU;EAAW,KAAK,KAAK;EAAO,CAAC,CAAC;CAE5F,MAAM,MAAM,KAAK,QAAQ;AACzB,KAAI,QAAQ,KAAA,EAAW,QAAO,OAAO;AACrC,QAAO,OAAO,WACZ,mBAAmB,IAAI,CAAC,KAAK,OAAO,KAAK,WAAuB,EAAE,OAAO,EAAE,CAAC,CAC7E;;;AAIH,MAAa,uBAAuB,SAAiB,YACnD,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,EAAE,SAAS,OAAO,UAAU,QAAQ;CAC1C,MAAM,cAAc,aAAa,KAAK,wBAAwB,KAAK;CACnE,MAAM,WAAW,OAAO,OAAO,QAAQ,YAAY,CAAC,KAAK,OAAO,SAAS,iBAAiB,CAAC;AAC3F,KAAI,SAAS,UAAU,KAAK;EAC1B,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,oBAAoB,GAAG,CAAC;AACtE,SAAO,OAAO,KAAK,gBAAgB,SAAS,QAAQ,KAAK,CAAC;;AAE5D,QAAO,SAAS,OAAO,KACrB,OAAO,SAAS,iBAAiB,EACjC,MAAM,WACN,MAAM,MAAM,WAAW,EACvB,OAAO,UACJ,UACC,IAAI,QAAQ,iBAAiB;EAC3B,UAAU;EACV,KAAK;GAAE,SAAS;GAAuB;GAAO;EAC/C,CAAC,CACL,EACD,OAAO,QAAQ,aAAa,CAC7B;EACD,CACH;AAEH,MAAM,qBACJ,SACA,aACsD;AAStD,QARgE,OAAO,KACrE,IAAI,QAAQ,YAAY;EACtB,UAAU;EACV,YAAY;EACZ,QACE;EACH,CAAC,CAEO;;;AAIb,MAAa,gCACX,OAAO,KACL,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ;CACT,CAAC,CACH;;AAGH,MAAa,sCAET,OAAO,KACL,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ;CACT,CAAC,CACH;AAML,MAAa,QACX,QAEA,OAAO,IAAI,WAAW,aAAa,YAAY;CAC7C,aAAa,MACX,eAAe,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACnF,kBAAkB,MAChB,oBAAoB,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACxF,qBAAqB;CACrB,oBAAoB;CACpB,0BAA0B;CAC3B,EAAE;;;;;;AAOL,MAAa,SACX,QAEA,MAAM,MACJ,MAAM,OAAO,oBAAoB,KAAK,IAAI,CAAC,EAC3C,MAAM,OACJ,mBACA,OAAO,IACL,KAAK,IAAI,GACR,OAAiC;CAChC,aAAa,QACX,EAAE,WAAW,IAAgC;CAC/C,kBAAkB,QAChB,EAAE,gBAAgB,IAAgC;CACpD,qBAAqB,EAAE;CACvB,oBAAoB,EAAE;CACtB,0BAA0B,EAAE;CAC7B,EACF,CACF,CACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { r as InworldSttModel } from "./models-CPLZDcgt.mjs";
|
|
2
|
-
import { Context, Effect, Layer, Redacted
|
|
2
|
+
import { Context, Effect, Layer, Redacted } from "effect";
|
|
3
3
|
import { HttpClient } from "effect/unstable/http";
|
|
4
4
|
import * as AiError from "@effect-uai/core/AiError";
|
|
5
5
|
import { CommonTranscribeRequest, Transcriber, TranscriberService } from "@effect-uai/core/Transcriber";
|
|
6
|
-
import { TranscriptResult
|
|
6
|
+
import { TranscriptResult } from "@effect-uai/core/Transcript";
|
|
7
7
|
|
|
8
8
|
//#region src/InworldTranscriber.d.ts
|
|
9
9
|
declare namespace InworldTranscriber_d_exports {
|
|
@@ -31,11 +31,7 @@ type Config = {
|
|
|
31
31
|
readonly baseUrl?: string;
|
|
32
32
|
};
|
|
33
33
|
/** Exported for reuse by `InworldRealtimeTranscriber`. */
|
|
34
|
-
declare const transcribeImpl: (cfg: Config) => (request: InworldTranscribeRequest) => Effect.Effect<
|
|
35
|
-
raw: Schema.Json;
|
|
36
|
-
words?: WordTimestamp[];
|
|
37
|
-
text: string;
|
|
38
|
-
}, AiError.AiError, HttpClient.HttpClient>;
|
|
34
|
+
declare const transcribeImpl: (cfg: Config) => (request: InworldTranscribeRequest) => Effect.Effect<any, any, unknown>;
|
|
39
35
|
declare const make: (cfg: Config) => Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient>;
|
|
40
36
|
/**
|
|
41
37
|
* Sync-only Layer. Registers `InworldTranscriber` + the generic
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldTranscriber.d.mts","names":[],"sources":["../src/InworldTranscriber.ts"],"mappings":";;;;;;;;;;;;;AAkCA;;;KAAY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,eAAA;EAAA,SACP,aAAA;EAAA,SACA,eAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GACP,CAAA,EAAG,wBAAA,KACA,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA,CAAQ,OAAA;EAAA,SACpC,uBAAA,EAAyB,kBAAA;AAAA;AAAA,cACnC,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;cAwFvD,cAAA,GAAkB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA
|
|
1
|
+
{"version":3,"file":"InworldTranscriber.d.mts","names":[],"sources":["../src/InworldTranscriber.ts"],"mappings":";;;;;;;;;;;;;AAkCA;;;KAAY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,eAAA;EAAA,SACP,aAAA;EAAA,SACA,eAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GACP,CAAA,EAAG,wBAAA,KACA,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA,CAAQ,OAAA;EAAA,SACpC,uBAAA,EAAyB,kBAAA;AAAA;AAAA,cACnC,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;cAwFvD,cAAA,GAAkB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA;AAAA,cAwDpE,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;;;;cAYjD,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,WAAA,SAAoB,UAAA,CAAW,UAAA"}
|
|
@@ -102,7 +102,7 @@ const streamUnsupported = (_audioIn, _request) => {
|
|
|
102
102
|
reason: "This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeTranscriber` to use the WS streamTranscriptionFrom path."
|
|
103
103
|
}));
|
|
104
104
|
};
|
|
105
|
-
const make = (cfg) => Effect.map(HttpClient.HttpClient
|
|
105
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient, (client) => ({
|
|
106
106
|
transcribe: (request) => transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
107
107
|
streamTranscriptionFrom: streamUnsupported
|
|
108
108
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InworldTranscriber.mjs","names":[],"sources":["../src/InworldTranscriber.ts"],"sourcesContent":["/**\n * Sync transcription via Inworld's REST endpoint.\n *\n * - `transcribe` → `POST /stt/v1/transcribe` with audio as base64 in\n * `audioData.content`. URL input is not accepted by Inworld — the\n * adapter rejects `_tag: \"url\"` audio sources with `InvalidRequest`.\n *\n * Streaming transcription lives at the `InworldRealtimeTranscriber`\n * subpath, which adds the WS path and the `SttStreaming` capability marker.\n */\nimport { Context, Effect, Encoding, Layer, Match, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioSource } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport type { TranscriptEvent, TranscriptResult, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport {\n type CommonStreamTranscribeRequest,\n type CommonTranscribeRequest,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport { authHeader, httpStatusError, transportFailure } from \"./codec.js\"\nimport type { InworldSttModel } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed transcribe request. `numberOfChannels` defaults to 1.\n * `audioEncoding` is autodetected from the audio MIME by default; pass\n * an explicit value to override (useful for raw PCM bytes).\n */\nexport type InworldTranscribeRequest = Omit<CommonTranscribeRequest, \"model\"> & {\n readonly model: InworldSttModel\n readonly audioEncoding?: \"AUTO_DETECT\" | \"LINEAR16\" | \"MP3\" | \"OGG_OPUS\" | \"FLAC\"\n readonly sampleRateHertz?: number\n readonly numberOfChannels?: number\n}\n\nexport type InworldTranscriberService = {\n readonly transcribe: (\n r: InworldTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n readonly streamTranscriptionFrom: TranscriberService[\"streamTranscriptionFrom\"]\n}\n\nexport class InworldTranscriber extends Context.Service<\n InworldTranscriber,\n InworldTranscriberService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldTranscriber\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// AudioSource → base64. Inworld's sync endpoint takes inline base64 only.\n// ---------------------------------------------------------------------------\n\nconst urlNotSupported: AiError.AiError = new AiError.InvalidRequest({\n provider: \"inworld\",\n param: \"audio\",\n raw: 'Inworld accepts only inline base64. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }`.',\n})\n\nconst audioToBase64: (audio: AudioSource) => Effect.Effect<string, AiError.AiError> =\n Match.type<AudioSource>().pipe(\n Match.tag(\"bytes\", (a) => Effect.succeed(Encoding.encodeBase64(a.bytes))),\n Match.tag(\"base64\", (a) => Effect.succeed(a.base64)),\n Match.tag(\"url\", () => Effect.fail(urlNotSupported)),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\nconst buildBody = (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const content = yield* audioToBase64(request.audio)\n // Inworld's `prompts` is a vocab-biasing term list — maps from\n // `biasingTerms`. There's no free-form prompt field, so `prompt` warns.\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"inworld\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"Inworld STT has no free-form prompt field; bias via `biasingTerms`.\",\n })\n return {\n transcribeConfig: {\n modelId: request.model,\n audioEncoding: request.audioEncoding ?? \"AUTO_DETECT\",\n ...(request.sampleRateHertz !== undefined && {\n sampleRateHertz: request.sampleRateHertz,\n }),\n numberOfChannels: request.numberOfChannels ?? 1,\n ...(request.language !== undefined && { language: request.language }),\n ...(request.biasingTerms !== undefined && { prompts: request.biasingTerms }),\n ...(request.wordTimestamps === true && { includeWordTimestamps: true }),\n },\n audioData: { content },\n }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schema\n// ---------------------------------------------------------------------------\n\nconst WireWord = Schema.Struct({\n word: Schema.String,\n startTimeMs: Schema.optional(Schema.Number),\n endTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n})\n\nconst WireResponse = Schema.Struct({\n transcription: Schema.Struct({\n transcript: Schema.String,\n isFinal: Schema.optional(Schema.Boolean),\n wordTimestamps: Schema.optional(Schema.NullOr(Schema.Array(WireWord))),\n }),\n})\nconst decodeResponse = Schema.decodeUnknownEffect(WireResponse)\n\nconst wireWordToCommon = (w: typeof WireWord.Type): WordTimestamp | undefined =>\n w.startTimeMs === undefined || w.endTimeMs === undefined\n ? undefined\n : {\n text: w.word,\n startSeconds: w.startTimeMs / 1000,\n endSeconds: w.endTimeMs / 1000,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n }\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\n/** Exported for reuse by `InworldRealtimeTranscriber`. */\nexport const transcribeImpl = (cfg: Config) => (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const body = yield* buildBody(request)\n const httpRequest = HttpClientRequest.post(`${baseUrl(cfg)}/stt/v1/transcribe`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"STT response missing `transcription.transcript`\", cause, json },\n }),\n ),\n )\n const words = wire.transcription.wordTimestamps\n ?.map(wireWordToCommon)\n .filter((w): w is WordTimestamp => w !== undefined)\n return {\n text: wire.transcription.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n raw: json,\n } satisfies TranscriptResult\n })\n\n// ---------------------------------------------------------------------------\n// streamTranscriptionFrom Unsupported on this Layer\n// ---------------------------------------------------------------------------\n\nconst streamUnsupported = <E, R>(\n _audioIn: Stream.Stream<Uint8Array, E, R>,\n _request: CommonStreamTranscribeRequest,\n): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> => {\n const fail: Stream.Stream<TranscriptEvent, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamTranscriptionFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeTranscriber` to use the WS streamTranscriptionFrom path.\",\n }),\n )\n return fail\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient.asEffect(), (client) => ({\n transcribe: (request) =>\n transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: streamUnsupported,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldTranscriber` + the generic\n * `Transcriber`. Does **not** register `SttStreaming` — for live\n * transcription use `@effect-uai/inworld/InworldRealtimeTranscriber`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldTranscriber | Transcriber, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(\n make(cfg),\n (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n }),\n ),\n ),\n )\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InworldTranscriber.mjs","names":[],"sources":["../src/InworldTranscriber.ts"],"sourcesContent":["/**\n * Sync transcription via Inworld's REST endpoint.\n *\n * - `transcribe` → `POST /stt/v1/transcribe` with audio as base64 in\n * `audioData.content`. URL input is not accepted by Inworld — the\n * adapter rejects `_tag: \"url\"` audio sources with `InvalidRequest`.\n *\n * Streaming transcription lives at the `InworldRealtimeTranscriber`\n * subpath, which adds the WS path and the `SttStreaming` capability marker.\n */\nimport { Context, Effect, Encoding, Layer, Match, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioSource } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport type { TranscriptEvent, TranscriptResult, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport {\n type CommonStreamTranscribeRequest,\n type CommonTranscribeRequest,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport { authHeader, httpStatusError, transportFailure } from \"./codec.js\"\nimport type { InworldSttModel } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed transcribe request. `numberOfChannels` defaults to 1.\n * `audioEncoding` is autodetected from the audio MIME by default; pass\n * an explicit value to override (useful for raw PCM bytes).\n */\nexport type InworldTranscribeRequest = Omit<CommonTranscribeRequest, \"model\"> & {\n readonly model: InworldSttModel\n readonly audioEncoding?: \"AUTO_DETECT\" | \"LINEAR16\" | \"MP3\" | \"OGG_OPUS\" | \"FLAC\"\n readonly sampleRateHertz?: number\n readonly numberOfChannels?: number\n}\n\nexport type InworldTranscriberService = {\n readonly transcribe: (\n r: InworldTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n readonly streamTranscriptionFrom: TranscriberService[\"streamTranscriptionFrom\"]\n}\n\nexport class InworldTranscriber extends Context.Service<\n InworldTranscriber,\n InworldTranscriberService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldTranscriber\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// AudioSource → base64. Inworld's sync endpoint takes inline base64 only.\n// ---------------------------------------------------------------------------\n\nconst urlNotSupported: AiError.AiError = new AiError.InvalidRequest({\n provider: \"inworld\",\n param: \"audio\",\n raw: 'Inworld accepts only inline base64. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }`.',\n})\n\nconst audioToBase64: (audio: AudioSource) => Effect.Effect<string, AiError.AiError> =\n Match.type<AudioSource>().pipe(\n Match.tag(\"bytes\", (a) => Effect.succeed(Encoding.encodeBase64(a.bytes))),\n Match.tag(\"base64\", (a) => Effect.succeed(a.base64)),\n Match.tag(\"url\", () => Effect.fail(urlNotSupported)),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\nconst buildBody = (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const content = yield* audioToBase64(request.audio)\n // Inworld's `prompts` is a vocab-biasing term list — maps from\n // `biasingTerms`. There's no free-form prompt field, so `prompt` warns.\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"inworld\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"Inworld STT has no free-form prompt field; bias via `biasingTerms`.\",\n })\n return {\n transcribeConfig: {\n modelId: request.model,\n audioEncoding: request.audioEncoding ?? \"AUTO_DETECT\",\n ...(request.sampleRateHertz !== undefined && {\n sampleRateHertz: request.sampleRateHertz,\n }),\n numberOfChannels: request.numberOfChannels ?? 1,\n ...(request.language !== undefined && { language: request.language }),\n ...(request.biasingTerms !== undefined && { prompts: request.biasingTerms }),\n ...(request.wordTimestamps === true && { includeWordTimestamps: true }),\n },\n audioData: { content },\n }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schema\n// ---------------------------------------------------------------------------\n\nconst WireWord = Schema.Struct({\n word: Schema.String,\n startTimeMs: Schema.optional(Schema.Number),\n endTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n})\n\nconst WireResponse = Schema.Struct({\n transcription: Schema.Struct({\n transcript: Schema.String,\n isFinal: Schema.optional(Schema.Boolean),\n wordTimestamps: Schema.optional(Schema.NullOr(Schema.Array(WireWord))),\n }),\n})\nconst decodeResponse = Schema.decodeUnknownEffect(WireResponse)\n\nconst wireWordToCommon = (w: typeof WireWord.Type): WordTimestamp | undefined =>\n w.startTimeMs === undefined || w.endTimeMs === undefined\n ? undefined\n : {\n text: w.word,\n startSeconds: w.startTimeMs / 1000,\n endSeconds: w.endTimeMs / 1000,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n }\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\n/** Exported for reuse by `InworldRealtimeTranscriber`. */\nexport const transcribeImpl = (cfg: Config) => (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const body = yield* buildBody(request)\n const httpRequest = HttpClientRequest.post(`${baseUrl(cfg)}/stt/v1/transcribe`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"STT response missing `transcription.transcript`\", cause, json },\n }),\n ),\n )\n const words = wire.transcription.wordTimestamps\n ?.map(wireWordToCommon)\n .filter((w): w is WordTimestamp => w !== undefined)\n return {\n text: wire.transcription.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n raw: json,\n } satisfies TranscriptResult\n })\n\n// ---------------------------------------------------------------------------\n// streamTranscriptionFrom Unsupported on this Layer\n// ---------------------------------------------------------------------------\n\nconst streamUnsupported = <E, R>(\n _audioIn: Stream.Stream<Uint8Array, E, R>,\n _request: CommonStreamTranscribeRequest,\n): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> => {\n const fail: Stream.Stream<TranscriptEvent, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamTranscriptionFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeTranscriber` to use the WS streamTranscriptionFrom path.\",\n }),\n )\n return fail\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n transcribe: (request) =>\n transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: streamUnsupported,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldTranscriber` + the generic\n * `Transcriber`. Does **not** register `SttStreaming` — for live\n * transcription use `@effect-uai/inworld/InworldRealtimeTranscriber`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldTranscriber | Transcriber, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(\n make(cfg),\n (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n }),\n ),\n ),\n )\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-uai/inworld",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Inworld speech-to-text and text-to-speech provider for @effect-uai/core.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/ws": "^8.5.13",
|
|
61
|
-
"effect": "4.0.0-beta.
|
|
61
|
+
"effect": "4.0.0-beta.94",
|
|
62
62
|
"typescript": "^6.0.3",
|
|
63
63
|
"ws": "^8.18.0",
|
|
64
|
-
"@effect-uai/core": "0.
|
|
64
|
+
"@effect-uai/core": "0.11.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"@effect-uai/core": ">=0.2.0 <1",
|
|
68
|
-
"effect": "4.0.0-beta.
|
|
68
|
+
"effect": ">=4.0.0-beta.94 <5.0.0",
|
|
69
69
|
"ws": "^8.0.0"
|
|
70
70
|
},
|
|
71
71
|
"peerDependenciesMeta": {
|
|
@@ -243,7 +243,7 @@ export const streamDialogueUnsupportedImpl: SpeechSynthesizerService["streamSynt
|
|
|
243
243
|
export const make = (
|
|
244
244
|
cfg: Config,
|
|
245
245
|
): Effect.Effect<InworldSynthesizerService, never, HttpClient.HttpClient> =>
|
|
246
|
-
Effect.map(HttpClient.HttpClient
|
|
246
|
+
Effect.map(HttpClient.HttpClient, (client) => ({
|
|
247
247
|
synthesize: (r) =>
|
|
248
248
|
synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
249
249
|
streamSynthesis: (r) =>
|
|
@@ -198,7 +198,7 @@ const streamUnsupported = <E, R>(
|
|
|
198
198
|
export const make = (
|
|
199
199
|
cfg: Config,
|
|
200
200
|
): Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient> =>
|
|
201
|
-
Effect.map(HttpClient.HttpClient
|
|
201
|
+
Effect.map(HttpClient.HttpClient, (client) => ({
|
|
202
202
|
transcribe: (request) =>
|
|
203
203
|
transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
204
204
|
streamTranscriptionFrom: streamUnsupported,
|