@effect-uai/inworld 0.5.1 → 0.6.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.
@@ -10,6 +10,8 @@ declare const make: (cfg: Config) => Effect.Effect<{
10
10
  synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<any, any, never>;
11
11
  streamSynthesis: (r: InworldSynthesizeRequest) => Stream.Stream<never, any, never>;
12
12
  streamSynthesisFrom: (textIn: any, request: any) => Stream.Stream<AudioChunk, any, unknown>;
13
+ synthesizeDialogue: SpeechSynthesizerService;
14
+ streamSynthesizeDialogue: SpeechSynthesizerService;
13
15
  }, never, HttpClient.HttpClient>;
14
16
  /**
15
17
  * Realtime Layer. Registers `InworldSynthesizer`, the generic
@@ -1 +1 @@
1
- {"version":3,"file":"InworldRealtimeSynthesizer.d.mts","names":[],"sources":["../src/InworldRealtimeSynthesizer.ts"],"mappings":";;;;;;;;cAoCa,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAM,MAAA,CAAA,MAAA;;;;;;;;;;;;cAqBnB,KAAA,GAAS,GAAA,EAAK,MAAA,KAAM,KAAA,CAAA,KAAA,iBAAA,UAAA,CAAA,UAAA"}
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"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
- import { InworldSynthesizer, streamSynthesisImpl, synthesizeImpl } from "./InworldSynthesizer.mjs";
2
+ import { InworldSynthesizer, dialogueUnsupportedImpl, streamDialogueUnsupportedImpl, streamSynthesisImpl, synthesizeImpl } from "./InworldSynthesizer.mjs";
3
3
  import { streamSynthesis } from "./realtimeTts.mjs";
4
4
  import { Effect, Layer, Stream } from "effect";
5
5
  import { HttpClient } from "effect/unstable/http";
@@ -23,7 +23,9 @@ var InworldRealtimeSynthesizer_exports = /* @__PURE__ */ __exportAll({
23
23
  const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (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
- streamSynthesisFrom: (textIn, request) => streamSynthesis(cfg)(textIn, request)
26
+ streamSynthesisFrom: (textIn, request) => streamSynthesis(cfg)(textIn, request),
27
+ synthesizeDialogue: dialogueUnsupportedImpl,
28
+ streamSynthesizeDialogue: streamDialogueUnsupportedImpl
27
29
  }));
28
30
  /**
29
31
  * Realtime Layer. Registers `InworldSynthesizer`, the generic
@@ -35,7 +37,9 @@ const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => (
35
37
  const layer = (cfg) => Layer.mergeAll(Layer.effect(InworldSynthesizer, make(cfg)), Layer.effect(SpeechSynthesizer, Effect.map(make(cfg), (s) => ({
36
38
  synthesize: (req) => s.synthesize(req),
37
39
  streamSynthesis: (req) => s.streamSynthesis(req),
38
- streamSynthesisFrom: (textIn, req) => s.streamSynthesisFrom(textIn, req)
40
+ streamSynthesisFrom: (textIn, req) => s.streamSynthesisFrom(textIn, req),
41
+ synthesizeDialogue: s.synthesizeDialogue,
42
+ streamSynthesizeDialogue: s.streamSynthesizeDialogue
39
43
  }))), Layer.succeed(TtsIncrementalText, void 0));
40
44
  //#endregion
41
45
  export { InworldSynthesizer, layer, make, InworldRealtimeSynthesizer_exports as t };
@@ -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 InworldSynthesizer,\n type InworldSynthesizerService,\n type InworldSynthesizeRequest,\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.asEffect(),\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 }) 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 }),\n ),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,WAAW,UAAU,GAC/B,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;CACnE,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;CACrC,EACF,CACF,EACD,MAAM,QAAQ,oBAAoB,KAAA,EAAU,CAC7C"}
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.asEffect(),\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,WAAW,UAAU,GAC/B,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"}
@@ -8,7 +8,7 @@ import { AudioBlob, AudioChunk } from "@effect-uai/core/Audio";
8
8
 
9
9
  //#region src/InworldSynthesizer.d.ts
10
10
  declare namespace InworldSynthesizer_d_exports {
11
- export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, buildBody, layer, make, streamSynthesisImpl, synthesizeImpl };
11
+ export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, buildBody, dialogueUnsupportedImpl, layer, make, streamDialogueUnsupportedImpl, streamSynthesisImpl, synthesizeImpl };
12
12
  }
13
13
  /**
14
14
  * Inworld-typed synthesize request.
@@ -30,6 +30,8 @@ type InworldSynthesizerService = {
30
30
  readonly synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>;
31
31
  readonly streamSynthesis: (r: InworldSynthesizeRequest) => Stream.Stream<AudioChunk, AiError.AiError>;
32
32
  readonly streamSynthesisFrom: SpeechSynthesizerService["streamSynthesisFrom"];
33
+ readonly synthesizeDialogue: SpeechSynthesizerService["synthesizeDialogue"];
34
+ readonly streamSynthesizeDialogue: SpeechSynthesizerService["streamSynthesizeDialogue"];
33
35
  };
34
36
  declare const InworldSynthesizer_base: Context.ServiceClass<InworldSynthesizer, "@betalyra/effect-uai/providers/inworld/InworldSynthesizer", InworldSynthesizerService>;
35
37
  declare class InworldSynthesizer extends InworldSynthesizer_base {}
@@ -44,7 +46,7 @@ declare const buildBody: (r: InworldSynthesizeRequest) => Effect.Effect<{
44
46
  temperature?: number;
45
47
  deliveryMode?: InworldDeliveryMode;
46
48
  language?: any;
47
- text: any;
49
+ text: string;
48
50
  voiceId: string;
49
51
  modelId: InworldTtsModel;
50
52
  audioConfig: AudioConfig;
@@ -55,6 +57,10 @@ declare const buildBody: (r: InworldSynthesizeRequest) => Effect.Effect<{
55
57
  declare const synthesizeImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Effect.Effect<any, any, HttpClient.HttpClient>;
56
58
  /** Exported for reuse by `InworldRealtimeSynthesizer`. */
57
59
  declare const streamSynthesisImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Stream.Stream<never, any, HttpClient.HttpClient>;
60
+ /** Exported for reuse by `InworldRealtimeSynthesizer`. */
61
+ declare const dialogueUnsupportedImpl: SpeechSynthesizerService["synthesizeDialogue"];
62
+ /** Exported for reuse by `InworldRealtimeSynthesizer`. */
63
+ declare const streamDialogueUnsupportedImpl: SpeechSynthesizerService["streamSynthesizeDialogue"];
58
64
  declare const make: (cfg: Config) => Effect.Effect<InworldSynthesizerService, never, HttpClient.HttpClient>;
59
65
  /**
60
66
  * Sync-only Layer. Registers `InworldSynthesizer` + the generic
@@ -63,5 +69,5 @@ declare const make: (cfg: Config) => Effect.Effect<InworldSynthesizerService, ne
63
69
  */
64
70
  declare const layer: (cfg: Config) => Layer.Layer<InworldSynthesizer | SpeechSynthesizer, never, HttpClient.HttpClient>;
65
71
  //#endregion
66
- export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, buildBody, layer, make, streamSynthesisImpl, synthesizeImpl, InworldSynthesizer_d_exports as t };
72
+ export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, buildBody, dialogueUnsupportedImpl, layer, make, streamDialogueUnsupportedImpl, streamSynthesisImpl, synthesizeImpl, InworldSynthesizer_d_exports as t };
67
73
  //# sourceMappingURL=InworldSynthesizer.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InworldSynthesizer.d.mts","names":[],"sources":["../src/InworldSynthesizer.ts"],"mappings":";;;;;;;;;;;;;;;AA8CA;;;;;;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;AAAA;AAAA,cAC/B,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;cAOvD,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;AAAA,cA8CzE,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;;;;cAcjD,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,iBAAA,SAA0B,UAAA,CAAW,UAAA"}
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;;cA2BvD,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"}
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
2
  import { audioConfigFor, authHeader, decodeAudioContent, defaultFormat, httpStatusError, transportFailure } from "./codec.mjs";
3
- import { Context, Effect, Layer, Schema, Stream } from "effect";
3
+ import { Array, Context, Effect, Layer, Schema, Stream } from "effect";
4
4
  import { HttpClient, HttpClientRequest } from "effect/unstable/http";
5
5
  import { SpeechSynthesizer } from "@effect-uai/core/SpeechSynthesizer";
6
6
  import * as AiError from "@effect-uai/core/AiError";
@@ -21,19 +21,32 @@ import * as JSONL from "@effect-uai/core/JSONL";
21
21
  var InworldSynthesizer_exports = /* @__PURE__ */ __exportAll({
22
22
  InworldSynthesizer: () => InworldSynthesizer,
23
23
  buildBody: () => buildBody,
24
+ dialogueUnsupportedImpl: () => dialogueUnsupportedImpl,
24
25
  layer: () => layer,
25
26
  make: () => make,
27
+ streamDialogueUnsupportedImpl: () => streamDialogueUnsupportedImpl,
26
28
  streamSynthesisImpl: () => streamSynthesisImpl,
27
29
  synthesizeImpl: () => synthesizeImpl
28
30
  });
29
31
  var InworldSynthesizer = class extends Context.Service()("@betalyra/effect-uai/providers/inworld/InworldSynthesizer") {};
32
+ /**
33
+ * Inworld accepts inline phoneme overrides as `/ipa/` tokens directly
34
+ * in the text — no separate field. Only IPA is supported; entries with
35
+ * other encodings are silently dropped (audio still renders with the
36
+ * default pronunciation). Whole-word, case-insensitive replacement.
37
+ */
38
+ const escapeForRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
39
+ const applyPronunciations = (text, pronunciations) => {
40
+ if (pronunciations === void 0) return text;
41
+ return Array.reduce(pronunciations, text, (acc, p) => p.encoding === "ipa" ? acc.replace(new RegExp(`\\b${escapeForRegex(p.phrase)}\\b`, "i"), `/${p.pronunciation}/`) : acc);
42
+ };
30
43
  /** Exported for reuse by the realtime variant's BOS `create` frame. */
31
44
  const buildBody = (r) => Effect.gen(function* () {
32
45
  const format = r.outputFormat ?? defaultFormat;
33
46
  const audioConfig = yield* audioConfigFor(format, r.speed);
34
47
  return {
35
48
  body: {
36
- text: r.text,
49
+ text: applyPronunciations(r.text, r.pronunciations),
37
50
  voiceId: r.voiceId,
38
51
  modelId: r.model,
39
52
  audioConfig,
@@ -110,10 +123,24 @@ const streamUnsupported = (_textIn, _request) => {
110
123
  reason: "This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeSynthesizer` to use the WS streamSynthesisFrom path."
111
124
  }));
112
125
  };
126
+ /** Exported for reuse by `InworldRealtimeSynthesizer`. */
127
+ const dialogueUnsupportedImpl = () => Effect.fail(new AiError.Unsupported({
128
+ provider: "inworld",
129
+ capability: "synthesizeDialogue",
130
+ reason: "Inworld TTS has no multi-speaker endpoint."
131
+ }));
132
+ /** Exported for reuse by `InworldRealtimeSynthesizer`. */
133
+ const streamDialogueUnsupportedImpl = () => Stream.fail(new AiError.Unsupported({
134
+ provider: "inworld",
135
+ capability: "streamSynthesizeDialogue",
136
+ reason: "Inworld TTS has no multi-speaker endpoint."
137
+ }));
113
138
  const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => ({
114
139
  synthesize: (r) => synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),
115
140
  streamSynthesis: (r) => streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),
116
- streamSynthesisFrom: streamUnsupported
141
+ streamSynthesisFrom: streamUnsupported,
142
+ synthesizeDialogue: dialogueUnsupportedImpl,
143
+ streamSynthesizeDialogue: streamDialogueUnsupportedImpl
117
144
  }));
118
145
  /**
119
146
  * Sync-only Layer. Registers `InworldSynthesizer` + the generic
@@ -123,9 +150,11 @@ const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => (
123
150
  const layer = (cfg) => Layer.merge(Layer.effect(InworldSynthesizer, make(cfg)), Layer.effect(SpeechSynthesizer, Effect.map(make(cfg), (s) => ({
124
151
  synthesize: (req) => s.synthesize(req),
125
152
  streamSynthesis: (req) => s.streamSynthesis(req),
126
- streamSynthesisFrom: s.streamSynthesisFrom
153
+ streamSynthesisFrom: s.streamSynthesisFrom,
154
+ synthesizeDialogue: s.synthesizeDialogue,
155
+ streamSynthesizeDialogue: s.streamSynthesizeDialogue
127
156
  }))));
128
157
  //#endregion
129
- export { InworldSynthesizer, buildBody, layer, make, streamSynthesisImpl, synthesizeImpl, InworldSynthesizer_exports as t };
158
+ export { InworldSynthesizer, buildBody, dialogueUnsupportedImpl, layer, make, streamDialogueUnsupportedImpl, streamSynthesisImpl, synthesizeImpl, InworldSynthesizer_exports as t };
130
159
 
131
160
  //# sourceMappingURL=InworldSynthesizer.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"InworldSynthesizer.mjs","names":[],"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 { 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 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}\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/** 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: r.text,\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// ---------------------------------------------------------------------------\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 }))\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 }),\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. Only IPA is supported; entries with\n * other encodings are silently dropped (audio still renders with the\n * default pronunciation). Whole-word, 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 p.encoding === \"ipa\"\n ? acc.replace(new RegExp(`\\\\b${escapeForRegex(p.phrase)}\\\\b`, \"i\"), `/${p.pronunciation}/`)\n : acc,\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/inworld",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Inworld speech-to-text and text-to-speech provider for @effect-uai/core.",
5
5
  "keywords": [
6
6
  "ai",
@@ -61,7 +61,7 @@
61
61
  "effect": "4.0.0-beta.57",
62
62
  "typescript": "^6.0.3",
63
63
  "ws": "^8.18.0",
64
- "@effect-uai/core": "0.5.1"
64
+ "@effect-uai/core": "0.6.0"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "@effect-uai/core": ">=0.2.0 <1",
@@ -19,9 +19,11 @@ import {
19
19
  } from "@effect-uai/core/SpeechSynthesizer"
20
20
  import {
21
21
  type Config,
22
+ dialogueUnsupportedImpl,
22
23
  InworldSynthesizer,
23
24
  type InworldSynthesizerService,
24
25
  type InworldSynthesizeRequest,
26
+ streamDialogueUnsupportedImpl,
25
27
  streamSynthesisImpl,
26
28
  synthesizeImpl,
27
29
  } from "./InworldSynthesizer.js"
@@ -45,6 +47,8 @@ export const make = (cfg: Config) =>
45
47
  streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),
46
48
  streamSynthesisFrom: (textIn, request) =>
47
49
  realtimeStream(cfg)(textIn, request as InworldSynthesizeRequest),
50
+ synthesizeDialogue: dialogueUnsupportedImpl,
51
+ streamSynthesizeDialogue: streamDialogueUnsupportedImpl,
48
52
  }) satisfies InworldSynthesizerService,
49
53
  )
50
54
 
@@ -69,6 +73,8 @@ export const layer = (cfg: Config) =>
69
73
  s.streamSynthesis(req as InworldSynthesizeRequest),
70
74
  streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>
71
75
  s.streamSynthesisFrom(textIn, req),
76
+ synthesizeDialogue: s.synthesizeDialogue,
77
+ streamSynthesizeDialogue: s.streamSynthesizeDialogue,
72
78
  }),
73
79
  ),
74
80
  ),
@@ -10,7 +10,7 @@
10
10
  * `InworldRealtimeSynthesizer` subpath, which adds the WS path and the
11
11
  * `TtsIncrementalText` capability marker.
12
12
  */
13
- import { Context, Effect, Layer, Redacted, Schema, Stream } from "effect"
13
+ import { Array as Arr, Context, Effect, Layer, Redacted, Schema, Stream } from "effect"
14
14
  import { HttpClient, HttpClientRequest } from "effect/unstable/http"
15
15
  import * as AiError from "@effect-uai/core/AiError"
16
16
  import type { AudioBlob, AudioChunk } from "@effect-uai/core/Audio"
@@ -18,6 +18,7 @@ import * as JSONL from "@effect-uai/core/JSONL"
18
18
  import {
19
19
  type CommonStreamSynthesizeRequest,
20
20
  type CommonSynthesizeRequest,
21
+ type CustomPronunciation,
21
22
  SpeechSynthesizer,
22
23
  type SpeechSynthesizerService,
23
24
  } from "@effect-uai/core/SpeechSynthesizer"
@@ -58,6 +59,8 @@ export type InworldSynthesizerService = {
58
59
  r: InworldSynthesizeRequest,
59
60
  ) => Stream.Stream<AudioChunk, AiError.AiError>
60
61
  readonly streamSynthesisFrom: SpeechSynthesizerService["streamSynthesisFrom"]
62
+ readonly synthesizeDialogue: SpeechSynthesizerService["synthesizeDialogue"]
63
+ readonly streamSynthesizeDialogue: SpeechSynthesizerService["streamSynthesizeDialogue"]
61
64
  }
62
65
 
63
66
  export class InworldSynthesizer extends Context.Service<
@@ -71,13 +74,33 @@ export type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: st
71
74
  // Request body
72
75
  // ---------------------------------------------------------------------------
73
76
 
77
+ /**
78
+ * Inworld accepts inline phoneme overrides as `/ipa/` tokens directly
79
+ * in the text — no separate field. Only IPA is supported; entries with
80
+ * other encodings are silently dropped (audio still renders with the
81
+ * default pronunciation). Whole-word, case-insensitive replacement.
82
+ */
83
+ const escapeForRegex = (s: string): string => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
84
+
85
+ const applyPronunciations = (
86
+ text: string,
87
+ pronunciations: ReadonlyArray<CustomPronunciation> | undefined,
88
+ ): string => {
89
+ if (pronunciations === undefined) return text
90
+ return Arr.reduce(pronunciations, text, (acc, p) =>
91
+ p.encoding === "ipa"
92
+ ? acc.replace(new RegExp(`\\b${escapeForRegex(p.phrase)}\\b`, "i"), `/${p.pronunciation}/`)
93
+ : acc,
94
+ )
95
+ }
96
+
74
97
  /** Exported for reuse by the realtime variant's BOS `create` frame. */
75
98
  export const buildBody = (r: InworldSynthesizeRequest) =>
76
99
  Effect.gen(function* () {
77
100
  const format = r.outputFormat ?? defaultFormat
78
101
  const audioConfig = yield* audioConfigFor(format, r.speed)
79
102
  const body = {
80
- text: r.text,
103
+ text: applyPronunciations(r.text, r.pronunciations),
81
104
  voiceId: r.voiceId,
82
105
  modelId: r.model,
83
106
  audioConfig,
@@ -194,6 +217,27 @@ const streamUnsupported = <E, R>(
194
217
  return fail
195
218
  }
196
219
 
220
+ /** Exported for reuse by `InworldRealtimeSynthesizer`. */
221
+ export const dialogueUnsupportedImpl: SpeechSynthesizerService["synthesizeDialogue"] = () =>
222
+ Effect.fail(
223
+ new AiError.Unsupported({
224
+ provider: "inworld",
225
+ capability: "synthesizeDialogue",
226
+ reason: "Inworld TTS has no multi-speaker endpoint.",
227
+ }),
228
+ )
229
+
230
+ /** Exported for reuse by `InworldRealtimeSynthesizer`. */
231
+ export const streamDialogueUnsupportedImpl: SpeechSynthesizerService["streamSynthesizeDialogue"] =
232
+ () =>
233
+ Stream.fail(
234
+ new AiError.Unsupported({
235
+ provider: "inworld",
236
+ capability: "streamSynthesizeDialogue",
237
+ reason: "Inworld TTS has no multi-speaker endpoint.",
238
+ }),
239
+ )
240
+
197
241
  // ---------------------------------------------------------------------------
198
242
  // Constructors
199
243
  // ---------------------------------------------------------------------------
@@ -207,6 +251,8 @@ export const make = (
207
251
  streamSynthesis: (r) =>
208
252
  streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),
209
253
  streamSynthesisFrom: streamUnsupported,
254
+ synthesizeDialogue: dialogueUnsupportedImpl,
255
+ streamSynthesizeDialogue: streamDialogueUnsupportedImpl,
210
256
  }))
211
257
 
212
258
  /**
@@ -229,6 +275,8 @@ export const layer = (
229
275
  streamSynthesis: (req: CommonSynthesizeRequest) =>
230
276
  s.streamSynthesis(req as InworldSynthesizeRequest),
231
277
  streamSynthesisFrom: s.streamSynthesisFrom,
278
+ synthesizeDialogue: s.synthesizeDialogue,
279
+ streamSynthesizeDialogue: s.streamSynthesizeDialogue,
232
280
  }),
233
281
  ),
234
282
  ),