@effect-uai/mistral 0.8.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/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/Mistral.d.mts +48 -0
- package/dist/Mistral.d.mts.map +1 -0
- package/dist/Mistral.mjs +88 -0
- package/dist/Mistral.mjs.map +1 -0
- package/dist/MistralRealtimeTranscriber.d.mts +15 -0
- package/dist/MistralRealtimeTranscriber.d.mts.map +1 -0
- package/dist/MistralRealtimeTranscriber.mjs +34 -0
- package/dist/MistralRealtimeTranscriber.mjs.map +1 -0
- package/dist/MistralSynthesizer.d.mts +43 -0
- package/dist/MistralSynthesizer.d.mts.map +1 -0
- package/dist/MistralSynthesizer.mjs +121 -0
- package/dist/MistralSynthesizer.mjs.map +1 -0
- package/dist/MistralTranscriber.d.mts +44 -0
- package/dist/MistralTranscriber.d.mts.map +1 -0
- package/dist/MistralTranscriber.mjs +111 -0
- package/dist/MistralTranscriber.mjs.map +1 -0
- package/dist/audioCodec.d.mts +27 -0
- package/dist/audioCodec.d.mts.map +1 -0
- package/dist/audioCodec.mjs +82 -0
- package/dist/audioCodec.mjs.map +1 -0
- package/dist/chunk-CfYAbeIz.mjs +13 -0
- package/dist/codec.d.mts +100 -0
- package/dist/codec.d.mts.map +1 -0
- package/dist/codec.mjs +244 -0
- package/dist/codec.mjs.map +1 -0
- package/dist/codec.test.d.mts +1 -0
- package/dist/codec.test.mjs +13800 -0
- package/dist/codec.test.mjs.map +1 -0
- package/dist/http.d.mts +9 -0
- package/dist/http.d.mts.map +1 -0
- package/dist/http.mjs +41 -0
- package/dist/http.mjs.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +7 -0
- package/dist/magic-string.es-PAZgLX4h.mjs +1013 -0
- package/dist/magic-string.es-PAZgLX4h.mjs.map +1 -0
- package/dist/models-DnDmylpj.d.mts +22 -0
- package/dist/models-DnDmylpj.d.mts.map +1 -0
- package/dist/models.d.mts +2 -0
- package/dist/models.mjs +1 -0
- package/dist/realtimeStt-ClXWXbXX.d.mts +21 -0
- package/dist/realtimeStt-ClXWXbXX.d.mts.map +1 -0
- package/dist/realtimeStt.d.mts +2 -0
- package/dist/realtimeStt.mjs +136 -0
- package/dist/realtimeStt.mjs.map +1 -0
- package/package.json +82 -0
- package/src/Mistral.ts +189 -0
- package/src/MistralRealtimeTranscriber.ts +60 -0
- package/src/MistralSynthesizer.ts +285 -0
- package/src/MistralTranscriber.ts +224 -0
- package/src/audioCodec.ts +123 -0
- package/src/codec.test.ts +121 -0
- package/src/codec.ts +338 -0
- package/src/http.ts +46 -0
- package/src/index.ts +6 -0
- package/src/models.ts +47 -0
- package/src/realtimeStt.ts +256 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Betalyra Sociedade Unipessoal Lda.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @effect-uai/mistral
|
|
2
|
+
|
|
3
|
+
Mistral provider for [`@effect-uai/core`](https://www.npmjs.com/package/@effect-uai/core).
|
|
4
|
+
|
|
5
|
+
One package, the whole Mistral surface:
|
|
6
|
+
|
|
7
|
+
- **`Mistral`** — the `LanguageModel` contract against Mistral's
|
|
8
|
+
chat-completions API, with SSE streaming, function calling, and
|
|
9
|
+
`json_schema` structured output.
|
|
10
|
+
- **`MistralTranscriber`** — batch speech-to-text (Voxtral) via
|
|
11
|
+
`/v1/audio/transcriptions`.
|
|
12
|
+
- **`MistralRealtimeTranscriber`** — live speech-to-text over the
|
|
13
|
+
Voxtral Realtime WebSocket (registers the `SttStreaming` capability).
|
|
14
|
+
- **`MistralSynthesizer`** — Voxtral text-to-speech, including streaming
|
|
15
|
+
output and zero-shot voice cloning via a reference clip.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pnpm add @effect-uai/mistral @effect-uai/core effect
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
ESM-only. Requires `effect@4.x` and `@effect-uai/core` as peers. The
|
|
24
|
+
realtime transcriber additionally needs the optional `ws` peer (Node /
|
|
25
|
+
Bun only).
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Chat completions (LanguageModel)
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { Config, Effect, Layer } from "effect"
|
|
33
|
+
import { FetchHttpClient } from "effect/unstable/http"
|
|
34
|
+
import { layer as mistralLayer } from "@effect-uai/mistral/Mistral"
|
|
35
|
+
|
|
36
|
+
const provider = Layer.unwrap(
|
|
37
|
+
Effect.gen(function* () {
|
|
38
|
+
const apiKey = yield* Config.redacted("MISTRAL_API_KEY")
|
|
39
|
+
return mistralLayer({ apiKey })
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
const layer = Layer.provide(provider, FetchHttpClient.layer)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The layer registers both the provider-typed `Mistral` tag and the
|
|
47
|
+
generic `LanguageModel` tag.
|
|
48
|
+
|
|
49
|
+
### Voxtral speech (STT + TTS)
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { layer as transcriber } from "@effect-uai/mistral/MistralRealtimeTranscriber"
|
|
53
|
+
import { layer as synthesizer } from "@effect-uai/mistral/MistralSynthesizer"
|
|
54
|
+
|
|
55
|
+
// transcriber({ apiKey }) registers Transcriber + SttStreaming
|
|
56
|
+
// synthesizer({ apiKey }) registers SpeechSynthesizer + TtsIncrementalText
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For batch (non-streaming) transcription, import
|
|
60
|
+
`@effect-uai/mistral/MistralTranscriber` instead — it omits the `ws`
|
|
61
|
+
dependency.
|
|
62
|
+
|
|
63
|
+
## Notes
|
|
64
|
+
|
|
65
|
+
- `tool_choice` maps `"required"` to Mistral's `"any"`.
|
|
66
|
+
- Voxtral TTS `pcm` output is float32 LE; `wav` is s16le.
|
|
67
|
+
- The realtime STT wire frames are reconstructed from the SDK; verify
|
|
68
|
+
against the live API before production use.
|
|
69
|
+
|
|
70
|
+
## Docs
|
|
71
|
+
|
|
72
|
+
<https://effect-uai.betalyra.com/providers/mistral/>
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { t as MistralModel } from "./models-DnDmylpj.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Redacted, Stream } from "effect";
|
|
3
|
+
import { HttpClient } from "effect/unstable/http";
|
|
4
|
+
import * as AiError from "@effect-uai/core/AiError";
|
|
5
|
+
import { CommonRequest, LanguageModel } from "@effect-uai/core/LanguageModel";
|
|
6
|
+
import { Turn, TurnEvent } from "@effect-uai/core/Turn";
|
|
7
|
+
|
|
8
|
+
//#region src/Mistral.d.ts
|
|
9
|
+
declare namespace Mistral_d_exports {
|
|
10
|
+
export { Config, Mistral, MistralRequest, MistralService, layer, make };
|
|
11
|
+
}
|
|
12
|
+
type MistralRequest = Omit<CommonRequest, "model"> & {
|
|
13
|
+
/**
|
|
14
|
+
* Narrows `CommonRequest.model` (`string`) to the typed `MistralModel`
|
|
15
|
+
* literal union for autocomplete.
|
|
16
|
+
*/
|
|
17
|
+
readonly model: MistralModel;
|
|
18
|
+
/**
|
|
19
|
+
* Prepend a safety system prompt (`safe_prompt` on the wire). Off by default.
|
|
20
|
+
*/
|
|
21
|
+
readonly safePrompt?: boolean; /** Deterministic sampling seed (`random_seed` on the wire). */
|
|
22
|
+
readonly randomSeed?: number;
|
|
23
|
+
};
|
|
24
|
+
type MistralService = {
|
|
25
|
+
/** Stream canonical `TurnEvent`s for one turn. */readonly streamTurn: (request: MistralRequest) => Stream.Stream<TurnEvent, AiError.AiError>; /** Drain a single turn and return the assembled `Turn`. */
|
|
26
|
+
readonly turn: (request: MistralRequest) => Effect.Effect<Turn, AiError.AiError>;
|
|
27
|
+
};
|
|
28
|
+
declare const Mistral_base: Context.ServiceClass<Mistral, "@betalyra/effect-uai/providers/mistral/Mistral", MistralService>;
|
|
29
|
+
/**
|
|
30
|
+
* Provider-typed service tag. Yield this when you want Mistral-specific options
|
|
31
|
+
* (`safePrompt`, `randomSeed`); yield the generic `LanguageModel` tag for
|
|
32
|
+
* provider-portable code. Both are registered by `layer`.
|
|
33
|
+
*/
|
|
34
|
+
declare class Mistral extends Mistral_base {}
|
|
35
|
+
type Config = {
|
|
36
|
+
readonly apiKey: Redacted.Redacted;
|
|
37
|
+
readonly baseUrl?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Build a `MistralService` value. For Layer-based setup, prefer `layer`. */
|
|
40
|
+
declare const make: (cfg: Config) => Effect.Effect<MistralService, never, HttpClient.HttpClient>;
|
|
41
|
+
/**
|
|
42
|
+
* Layer that registers both the provider-specific `Mistral` tag and the
|
|
43
|
+
* generic `LanguageModel` tag, sharing one underlying implementation.
|
|
44
|
+
*/
|
|
45
|
+
declare const layer: (cfg: Config) => Layer.Layer<Mistral | LanguageModel, never, HttpClient.HttpClient>;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { Config, Mistral, MistralRequest, MistralService, layer, make, Mistral_d_exports as t };
|
|
48
|
+
//# sourceMappingURL=Mistral.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mistral.d.mts","names":[],"sources":["../src/Mistral.ts"],"mappings":";;;;;;;;;;;KA+BY,cAAA,GAAiB,IAAA,CAAK,aAAA;;;;;WAKvB,KAAA,EAAO,YAAA;;;;WAIP,UAAA;WAEA,UAAA;AAAA;AAAA,KAGC,cAAA;EAdsB,2DAgBvB,UAAA,GAAa,OAAA,EAAS,cAAA,KAAmB,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,OAAA,GAXnE;EAAA,SAaP,IAAA,GAAO,OAAA,EAAS,cAAA,KAAmB,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,OAAA,CAAQ,OAAA;AAAA;AAAA,cACzE,YAAA;;;;;;cAOY,OAAA,SAAgB,YAAA;AAAA,KAIjB,MAAA;EAAA,SACD,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SACjB,OAAA;AAAA;;cAgGE,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAS,MAAA,CAAO,MAAA,CAAO,cAAA,SAAuB,UAAA,CAAW,UAAA;;;;;cActE,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,OAAA,GAAU,aAAA,SAAsB,UAAA,CAAW,UAAA"}
|
package/dist/Mistral.mjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
|
|
2
|
+
import { accumulatorToTurn, applyChunk, decodeChunk, emptyAccumulator, itemsToMessages, responseFormatWire, toolChoiceWire, toolsWire } from "./codec.mjs";
|
|
3
|
+
import { httpStatusError } from "./http.mjs";
|
|
4
|
+
import { Context, Effect, Layer, Option, Redacted, Result, Schema, Stream } from "effect";
|
|
5
|
+
import { HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
6
|
+
import * as AiError from "@effect-uai/core/AiError";
|
|
7
|
+
import { LanguageModel, turnFromStream } from "@effect-uai/core/LanguageModel";
|
|
8
|
+
import * as SSE from "@effect-uai/core/SSE";
|
|
9
|
+
import { descriptorsOf } from "@effect-uai/core/Tool";
|
|
10
|
+
import { TurnEvent } from "@effect-uai/core/Turn";
|
|
11
|
+
//#region src/Mistral.ts
|
|
12
|
+
var Mistral_exports = /* @__PURE__ */ __exportAll({
|
|
13
|
+
Mistral: () => Mistral,
|
|
14
|
+
layer: () => layer,
|
|
15
|
+
make: () => make
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Provider-typed service tag. Yield this when you want Mistral-specific options
|
|
19
|
+
* (`safePrompt`, `randomSeed`); yield the generic `LanguageModel` tag for
|
|
20
|
+
* provider-portable code. Both are registered by `layer`.
|
|
21
|
+
*/
|
|
22
|
+
var Mistral = class extends Context.Service()("@betalyra/effect-uai/providers/mistral/Mistral") {};
|
|
23
|
+
const buildRequestBody = (request) => {
|
|
24
|
+
const tools = toolsWire(descriptorsOf(request.tools));
|
|
25
|
+
return {
|
|
26
|
+
model: request.model,
|
|
27
|
+
stream: true,
|
|
28
|
+
messages: itemsToMessages(request.history),
|
|
29
|
+
...request.temperature !== void 0 && { temperature: request.temperature },
|
|
30
|
+
...request.topP !== void 0 && { top_p: request.topP },
|
|
31
|
+
...request.maxOutputTokens !== void 0 && { max_tokens: request.maxOutputTokens },
|
|
32
|
+
...request.safePrompt !== void 0 && { safe_prompt: request.safePrompt },
|
|
33
|
+
...request.randomSeed !== void 0 && { random_seed: request.randomSeed },
|
|
34
|
+
...Option.isSome(tools) && { tools: tools.value },
|
|
35
|
+
...request.toolChoice !== void 0 && { tool_choice: toolChoiceWire(request.toolChoice) },
|
|
36
|
+
...request.structured !== void 0 && { response_format: responseFormatWire(request.structured) }
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const parseJsonUnknown = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown));
|
|
40
|
+
/**
|
|
41
|
+
* Decode one SSE event's `data` payload into a `WireChunk`. Returns `None`
|
|
42
|
+
* for the `[DONE]` sentinel and for any payload that isn't a chunk we model,
|
|
43
|
+
* so a stray keep-alive never aborts the turn.
|
|
44
|
+
*/
|
|
45
|
+
const decodeEvent = (data) => data.trim() === "[DONE]" ? Effect.succeedNone : parseJsonUnknown(data).pipe(Effect.flatMap(decodeChunk), Effect.option);
|
|
46
|
+
const buildStream = (cfg) => {
|
|
47
|
+
const url = `${cfg.baseUrl ?? "https://api.mistral.ai"}/v1/chat/completions`;
|
|
48
|
+
return (request) => Stream.unwrap(Effect.gen(function* () {
|
|
49
|
+
const client = yield* HttpClient.HttpClient;
|
|
50
|
+
const httpRequest = HttpClientRequest.post(url).pipe(HttpClientRequest.setHeader("authorization", `Bearer ${Redacted.value(cfg.apiKey)}`), HttpClientRequest.bodyJsonUnsafe(buildRequestBody(request)), HttpClientRequest.accept("text/event-stream"));
|
|
51
|
+
const response = yield* client.execute(httpRequest).pipe(Effect.mapError((cause) => new AiError.Unavailable({
|
|
52
|
+
provider: "mistral",
|
|
53
|
+
raw: cause
|
|
54
|
+
})));
|
|
55
|
+
if (response.status >= 400) {
|
|
56
|
+
const text = yield* response.text.pipe(Effect.orElseSucceed(() => ""));
|
|
57
|
+
return Stream.fail(httpStatusError(response.status, text));
|
|
58
|
+
}
|
|
59
|
+
return response.stream.pipe(Stream.mapError((cause) => new AiError.Unavailable({
|
|
60
|
+
provider: "mistral",
|
|
61
|
+
raw: cause
|
|
62
|
+
})), SSE.fromBytes, Stream.mapEffect((ev) => decodeEvent(ev.data)), Stream.filterMap((chunk) => Option.isSome(chunk) ? Result.succeed(chunk.value) : Result.failVoid), Stream.mapAccum(() => emptyAccumulator, applyChunk, { onHalt: (acc) => [TurnEvent.TurnComplete({ turn: accumulatorToTurn(acc) })] }));
|
|
63
|
+
}));
|
|
64
|
+
};
|
|
65
|
+
/** Build a `MistralService` value. For Layer-based setup, prefer `layer`. */
|
|
66
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => {
|
|
67
|
+
const streamTurn = (request) => buildStream(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client));
|
|
68
|
+
return {
|
|
69
|
+
streamTurn,
|
|
70
|
+
turn: turnFromStream(streamTurn)
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Layer that registers both the provider-specific `Mistral` tag and the
|
|
75
|
+
* generic `LanguageModel` tag, sharing one underlying implementation.
|
|
76
|
+
*/
|
|
77
|
+
const layer = (cfg) => {
|
|
78
|
+
const typed = Layer.effect(Mistral, make(cfg));
|
|
79
|
+
const generic = Layer.effect(LanguageModel, Effect.map(make(cfg), (s) => ({
|
|
80
|
+
streamTurn: (request) => s.streamTurn(request),
|
|
81
|
+
turn: (request) => s.turn(request)
|
|
82
|
+
})));
|
|
83
|
+
return Layer.merge(typed, generic);
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { Mistral, layer, make, Mistral_exports as t };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=Mistral.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mistral.mjs","names":[],"sources":["../src/Mistral.ts"],"sourcesContent":["import { Context, Effect, Layer, Option, Redacted, Result, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport {\n type CommonRequest,\n LanguageModel,\n type LanguageModelService,\n turnFromStream,\n} from \"@effect-uai/core/LanguageModel\"\nimport * as SSE from \"@effect-uai/core/SSE\"\nimport { descriptorsOf } from \"@effect-uai/core/Tool\"\nimport { type Turn, TurnEvent } from \"@effect-uai/core/Turn\"\nimport {\n type Accumulator,\n type WireChunk,\n accumulatorToTurn,\n applyChunk,\n decodeChunk,\n emptyAccumulator,\n itemsToMessages,\n responseFormatWire,\n toolChoiceWire,\n toolsWire,\n} from \"./codec.js\"\nimport { httpStatusError } from \"./http.js\"\nimport type { MistralModel } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type MistralRequest = Omit<CommonRequest, \"model\"> & {\n /**\n * Narrows `CommonRequest.model` (`string`) to the typed `MistralModel`\n * literal union for autocomplete.\n */\n readonly model: MistralModel\n /**\n * Prepend a safety system prompt (`safe_prompt` on the wire). Off by default.\n */\n readonly safePrompt?: boolean\n /** Deterministic sampling seed (`random_seed` on the wire). */\n readonly randomSeed?: number\n}\n\nexport type MistralService = {\n /** Stream canonical `TurnEvent`s for one turn. */\n readonly streamTurn: (request: MistralRequest) => Stream.Stream<TurnEvent, AiError.AiError>\n /** Drain a single turn and return the assembled `Turn`. */\n readonly turn: (request: MistralRequest) => Effect.Effect<Turn, AiError.AiError>\n}\n\n/**\n * Provider-typed service tag. Yield this when you want Mistral-specific options\n * (`safePrompt`, `randomSeed`); yield the generic `LanguageModel` tag for\n * provider-portable code. Both are registered by `layer`.\n */\nexport class Mistral extends Context.Service<Mistral, MistralService>()(\n \"@betalyra/effect-uai/providers/mistral/Mistral\",\n) {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n}\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\nconst buildRequestBody = (request: MistralRequest): Record<string, unknown> => {\n const tools = toolsWire(descriptorsOf(request.tools))\n return {\n model: request.model,\n stream: true,\n messages: itemsToMessages(request.history),\n ...(request.temperature !== undefined && { temperature: request.temperature }),\n ...(request.topP !== undefined && { top_p: request.topP }),\n ...(request.maxOutputTokens !== undefined && { max_tokens: request.maxOutputTokens }),\n ...(request.safePrompt !== undefined && { safe_prompt: request.safePrompt }),\n ...(request.randomSeed !== undefined && { random_seed: request.randomSeed }),\n ...(Option.isSome(tools) && { tools: tools.value }),\n ...(request.toolChoice !== undefined && { tool_choice: toolChoiceWire(request.toolChoice) }),\n ...(request.structured !== undefined && {\n response_format: responseFormatWire(request.structured),\n }),\n }\n}\n\n// ---------------------------------------------------------------------------\n// SSE → WireChunk\n// ---------------------------------------------------------------------------\n\nconst parseJsonUnknown = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\n/**\n * Decode one SSE event's `data` payload into a `WireChunk`. Returns `None`\n * for the `[DONE]` sentinel and for any payload that isn't a chunk we model,\n * so a stray keep-alive never aborts the turn.\n */\nconst decodeEvent = (data: string): Effect.Effect<Option.Option<WireChunk>> =>\n data.trim() === \"[DONE]\"\n ? Effect.succeedNone\n : parseJsonUnknown(data).pipe(Effect.flatMap(decodeChunk), Effect.option)\n\n// ---------------------------------------------------------------------------\n// Stream\n// ---------------------------------------------------------------------------\n\nconst buildStream = (cfg: Config) => {\n const baseUrl = cfg.baseUrl ?? \"https://api.mistral.ai\"\n const url = `${baseUrl}/v1/chat/completions`\n return (\n request: MistralRequest,\n ): Stream.Stream<TurnEvent, AiError.AiError, HttpClient.HttpClient> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"authorization\", `Bearer ${Redacted.value(cfg.apiKey)}`),\n HttpClientRequest.bodyJsonUnsafe(buildRequestBody(request)),\n HttpClientRequest.accept(\"text/event-stream\"),\n )\n const response = yield* client\n .execute(httpRequest)\n .pipe(\n Effect.mapError(\n (cause): AiError.AiError =>\n new AiError.Unavailable({ provider: \"mistral\", raw: cause }),\n ),\n )\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n\n return response.stream.pipe(\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.Unavailable({ provider: \"mistral\", raw: cause }),\n ),\n SSE.fromBytes,\n Stream.mapEffect((ev) => decodeEvent(ev.data)),\n Stream.filterMap((chunk) =>\n Option.isSome(chunk) ? Result.succeed(chunk.value) : Result.failVoid,\n ),\n Stream.mapAccum((): Accumulator => emptyAccumulator, applyChunk, {\n onHalt: (acc) => [TurnEvent.TurnComplete({ turn: accumulatorToTurn(acc) })],\n }),\n )\n }),\n )\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\n/** Build a `MistralService` value. For Layer-based setup, prefer `layer`. */\nexport const make = (cfg: Config): Effect.Effect<MistralService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient.asEffect(), (client) => {\n const streamTurn: MistralService[\"streamTurn\"] = (request) =>\n buildStream(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client))\n return {\n streamTurn,\n turn: turnFromStream(streamTurn),\n }\n })\n\n/**\n * Layer that registers both the provider-specific `Mistral` tag and the\n * generic `LanguageModel` tag, sharing one underlying implementation.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<Mistral | LanguageModel, never, HttpClient.HttpClient> => {\n const typed = Layer.effect(Mistral, make(cfg))\n const generic = Layer.effect(\n LanguageModel,\n Effect.map(\n make(cfg),\n (s): LanguageModelService => ({\n streamTurn: (request) => s.streamTurn(request as MistralRequest),\n turn: (request) => s.turn(request as MistralRequest),\n }),\n ),\n )\n return Layer.merge(typed, generic)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MistralTranscribeRequest, MistralTranscriber, MistralTranscriberService } from "./MistralTranscriber.mjs";
|
|
2
|
+
import { t as Config } from "./realtimeStt-ClXWXbXX.mjs";
|
|
3
|
+
import { Effect, Layer } from "effect";
|
|
4
|
+
import { HttpClient } from "effect/unstable/http";
|
|
5
|
+
import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
|
|
6
|
+
|
|
7
|
+
//#region src/MistralRealtimeTranscriber.d.ts
|
|
8
|
+
declare namespace MistralRealtimeTranscriber_d_exports {
|
|
9
|
+
export { Config, MistralTranscribeRequest, MistralTranscriber, MistralTranscriberService, layer, make };
|
|
10
|
+
}
|
|
11
|
+
declare const make: (cfg: Config) => Effect.Effect<MistralTranscriberService, never, HttpClient.HttpClient>;
|
|
12
|
+
declare const layer: (cfg: Config) => Layer.Layer<MistralTranscriber | Transcriber | SttStreaming, never, HttpClient.HttpClient>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { type Config, type MistralTranscribeRequest, MistralTranscriber, type MistralTranscriberService, layer, make, MistralRealtimeTranscriber_d_exports as t };
|
|
15
|
+
//# sourceMappingURL=MistralRealtimeTranscriber.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MistralRealtimeTranscriber.d.mts","names":[],"sources":["../src/MistralRealtimeTranscriber.ts"],"mappings":";;;;;;;;;;cAiCa,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;AAAA,cAOjD,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,WAAA,GAAc,YAAA,SAAqB,UAAA,CAAW,UAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
|
|
2
|
+
import { MistralTranscriber, transcribeImpl } from "./MistralTranscriber.mjs";
|
|
3
|
+
import { streamTranscription } from "./realtimeStt.mjs";
|
|
4
|
+
import { Effect, Layer } from "effect";
|
|
5
|
+
import { HttpClient } from "effect/unstable/http";
|
|
6
|
+
import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
|
|
7
|
+
//#region src/MistralRealtimeTranscriber.ts
|
|
8
|
+
/**
|
|
9
|
+
* Realtime variant of `MistralTranscriber`. Wires `streamTranscriptionFrom`
|
|
10
|
+
* to the Voxtral Realtime WebSocket endpoint and registers the `SttStreaming`
|
|
11
|
+
* capability marker, so live-transcription calls compile against this Layer
|
|
12
|
+
* alone (unlike the sync-only `MistralTranscriber` Layer).
|
|
13
|
+
*
|
|
14
|
+
* Pulls in `ws` (optional peer dep) transitively via `./realtimeStt.js`.
|
|
15
|
+
* Node/Bun only — the browser `WebSocket` API can't set the `Authorization`
|
|
16
|
+
* header the WS upgrade requires.
|
|
17
|
+
*/
|
|
18
|
+
var MistralRealtimeTranscriber_exports = /* @__PURE__ */ __exportAll({
|
|
19
|
+
MistralTranscriber: () => MistralTranscriber,
|
|
20
|
+
layer: () => layer,
|
|
21
|
+
make: () => make
|
|
22
|
+
});
|
|
23
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => ({
|
|
24
|
+
transcribe: (request) => transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
25
|
+
streamTranscriptionFrom: streamTranscription(cfg)
|
|
26
|
+
}));
|
|
27
|
+
const layer = (cfg) => Layer.mergeAll(Layer.effect(MistralTranscriber, make(cfg)), Layer.effect(Transcriber, Effect.map(make(cfg), (s) => ({
|
|
28
|
+
transcribe: (req) => s.transcribe(req),
|
|
29
|
+
streamTranscriptionFrom: s.streamTranscriptionFrom
|
|
30
|
+
}))), Layer.succeed(SttStreaming, void 0));
|
|
31
|
+
//#endregion
|
|
32
|
+
export { MistralTranscriber, layer, make, MistralRealtimeTranscriber_exports as t };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=MistralRealtimeTranscriber.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MistralRealtimeTranscriber.mjs","names":[],"sources":["../src/MistralRealtimeTranscriber.ts"],"sourcesContent":["/**\n * Realtime variant of `MistralTranscriber`. Wires `streamTranscriptionFrom`\n * to the Voxtral Realtime WebSocket endpoint and registers the `SttStreaming`\n * capability marker, so live-transcription calls compile against this Layer\n * alone (unlike the sync-only `MistralTranscriber` Layer).\n *\n * Pulls in `ws` (optional peer dep) transitively via `./realtimeStt.js`.\n * Node/Bun only — the browser `WebSocket` API can't set the `Authorization`\n * header the WS upgrade requires.\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 MistralTranscriber,\n type MistralTranscriberService,\n type MistralTranscribeRequest,\n transcribeImpl,\n} from \"./MistralTranscriber.js\"\nimport { type Config, streamTranscription } from \"./realtimeStt.js\"\n\nexport type { Config } from \"./realtimeStt.js\"\nexport {\n MistralTranscriber,\n type MistralTranscriberService,\n type MistralTranscribeRequest,\n} from \"./MistralTranscriber.js\"\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<MistralTranscriberService, 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: streamTranscription(cfg),\n }))\n\nexport const layer = (\n cfg: Config,\n): Layer.Layer<MistralTranscriber | Transcriber | SttStreaming, never, HttpClient.HttpClient> =>\n Layer.mergeAll(\n Layer.effect(MistralTranscriber, 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 MistralTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n }),\n ),\n ),\n Layer.succeed(SttStreaming, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,QACX,QAEA,OAAO,IAAI,WAAW,WAAW,UAAU,GAAG,YAAY;CACxD,aAAa,YACX,eAAe,IAAI,CAAC,QAAQ,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACzF,yBAAyB,oBAAoB,IAAI;CAClD,EAAE;AAEL,MAAa,SACX,QAEA,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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { i as MistralTtsModel } from "./models-DnDmylpj.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Redacted, Stream } from "effect";
|
|
3
|
+
import { HttpClient } from "effect/unstable/http";
|
|
4
|
+
import * as AiError from "@effect-uai/core/AiError";
|
|
5
|
+
import { AudioBlob, AudioChunk } from "@effect-uai/core/Audio";
|
|
6
|
+
import { CommonStreamSynthesizeRequest, CommonSynthesizeRequest, SpeechSynthesizer, SpeechSynthesizerService, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
|
|
7
|
+
|
|
8
|
+
//#region src/MistralSynthesizer.d.ts
|
|
9
|
+
declare namespace MistralSynthesizer_d_exports {
|
|
10
|
+
export { Config, MistralSynthesizeRequest, MistralSynthesizer, MistralSynthesizerService, layer, make };
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Mistral-typed synthesize request. `model` narrows to `MistralTtsModel`;
|
|
14
|
+
* `voiceId` selects a saved Voxtral voice. `refAudio` (base64 of a 2-3s clip)
|
|
15
|
+
* triggers zero-shot voice cloning and takes precedence over `voiceId`.
|
|
16
|
+
*/
|
|
17
|
+
type MistralSynthesizeRequest = Omit<CommonSynthesizeRequest, "model"> & {
|
|
18
|
+
readonly model: MistralTtsModel;
|
|
19
|
+
readonly refAudio?: string;
|
|
20
|
+
};
|
|
21
|
+
type MistralSynthesizerService = {
|
|
22
|
+
readonly synthesize: (request: MistralSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>;
|
|
23
|
+
readonly streamSynthesis: (request: MistralSynthesizeRequest) => Stream.Stream<AudioChunk, AiError.AiError>;
|
|
24
|
+
readonly streamSynthesisFrom: <E, R>(textIn: Stream.Stream<string, E, R>, request: CommonStreamSynthesizeRequest) => Stream.Stream<AudioChunk, AiError.AiError | E, R>;
|
|
25
|
+
readonly synthesizeDialogue: SpeechSynthesizerService["synthesizeDialogue"];
|
|
26
|
+
readonly streamSynthesizeDialogue: SpeechSynthesizerService["streamSynthesizeDialogue"];
|
|
27
|
+
};
|
|
28
|
+
declare const MistralSynthesizer_base: Context.ServiceClass<MistralSynthesizer, "@betalyra/effect-uai/providers/mistral/MistralSynthesizer", MistralSynthesizerService>;
|
|
29
|
+
declare class MistralSynthesizer extends MistralSynthesizer_base {}
|
|
30
|
+
type Config = {
|
|
31
|
+
readonly apiKey: Redacted.Redacted;
|
|
32
|
+
readonly baseUrl?: string;
|
|
33
|
+
};
|
|
34
|
+
declare const make: (cfg: Config) => Effect.Effect<MistralSynthesizerService, never, HttpClient.HttpClient>;
|
|
35
|
+
/**
|
|
36
|
+
* Layer registering `MistralSynthesizer`, the generic `SpeechSynthesizer` tag,
|
|
37
|
+
* and the `TtsIncrementalText` capability marker (so `streamSynthesisFrom`
|
|
38
|
+
* composes — note the text side buffers; see its docs).
|
|
39
|
+
*/
|
|
40
|
+
declare const layer: (cfg: Config) => Layer.Layer<MistralSynthesizer | SpeechSynthesizer | TtsIncrementalText, never, HttpClient.HttpClient>;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { Config, MistralSynthesizeRequest, MistralSynthesizer, MistralSynthesizerService, layer, make, MistralSynthesizer_d_exports as t };
|
|
43
|
+
//# sourceMappingURL=MistralSynthesizer.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MistralSynthesizer.d.mts","names":[],"sources":["../src/MistralSynthesizer.ts"],"mappings":";;;;;;;;;;;;;;;;KAmCY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,eAAA;EAAA,SACP,QAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GACP,OAAA,EAAS,wBAAA,KACN,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,OAAA;EAAA,SAC7B,eAAA,GACP,OAAA,EAAS,wBAAA,KACN,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,OAAA;EAAA,SAC9B,mBAAA,SACP,MAAA,EAAQ,MAAA,CAAO,MAAA,SAAe,CAAA,EAAG,CAAA,GACjC,OAAA,EAAS,6BAAA,KACN,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,OAAA,GAAU,CAAA,EAAG,CAAA;EAAA,SAC3C,kBAAA,EAAoB,wBAAA;EAAA,SACpB,wBAAA,EAA0B,wBAAA;AAAA;AAAA,cACpC,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SACD,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SACjB,OAAA;AAAA;AAAA,cAmKE,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;AA3L9D;;;cA2Na,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CACP,kBAAA,GAAqB,iBAAA,GAAoB,kBAAA,SAEzC,UAAA,CAAW,UAAA"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
|
|
2
|
+
import { httpStatusError, transportFailure } from "./http.mjs";
|
|
3
|
+
import { containerToTtsFormat, realizedTtsFormat } from "./audioCodec.mjs";
|
|
4
|
+
import { Array, Context, Effect, Encoding, Layer, Result, Schema, Stream } from "effect";
|
|
5
|
+
import { HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
6
|
+
import * as AiError from "@effect-uai/core/AiError";
|
|
7
|
+
import * as Capabilities from "@effect-uai/core/Capabilities";
|
|
8
|
+
import { SpeechSynthesizer, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
|
|
9
|
+
//#region src/MistralSynthesizer.ts
|
|
10
|
+
var MistralSynthesizer_exports = /* @__PURE__ */ __exportAll({
|
|
11
|
+
MistralSynthesizer: () => MistralSynthesizer,
|
|
12
|
+
layer: () => layer,
|
|
13
|
+
make: () => make
|
|
14
|
+
});
|
|
15
|
+
var MistralSynthesizer = class extends Context.Service()("@betalyra/effect-uai/providers/mistral/MistralSynthesizer") {};
|
|
16
|
+
const defaultFormat = {
|
|
17
|
+
container: "mp3",
|
|
18
|
+
encoding: "mp3",
|
|
19
|
+
sampleRate: 24e3
|
|
20
|
+
};
|
|
21
|
+
const buildBody = (request) => Effect.gen(function* () {
|
|
22
|
+
if (request.pronunciations !== void 0 && request.pronunciations.length > 0) return yield* Effect.fail(new AiError.Unsupported({
|
|
23
|
+
provider: "mistral",
|
|
24
|
+
capability: "pronunciations",
|
|
25
|
+
reason: "Voxtral TTS has no phoneme field. Use a provider with a phoneme path (Inworld, Google) for pronunciation overrides."
|
|
26
|
+
}));
|
|
27
|
+
yield* Capabilities.warnDroppedWhen(request.speed, {
|
|
28
|
+
provider: "mistral",
|
|
29
|
+
capability: "speed",
|
|
30
|
+
field: "speed",
|
|
31
|
+
reason: "Voxtral TTS has no speed control; prosody follows the voice prompt."
|
|
32
|
+
});
|
|
33
|
+
yield* Capabilities.warnDroppedWhen(request.languageCode, {
|
|
34
|
+
provider: "mistral",
|
|
35
|
+
capability: "languageCode",
|
|
36
|
+
field: "languageCode",
|
|
37
|
+
reason: "Voxtral TTS auto-detects language and clones cross-lingually."
|
|
38
|
+
});
|
|
39
|
+
const responseFormat = yield* containerToTtsFormat((request.outputFormat ?? defaultFormat).container);
|
|
40
|
+
return {
|
|
41
|
+
body: {
|
|
42
|
+
model: request.model,
|
|
43
|
+
input: request.text,
|
|
44
|
+
response_format: responseFormat,
|
|
45
|
+
...request.refAudio !== void 0 ? { ref_audio: request.refAudio } : { voice_id: request.voiceId }
|
|
46
|
+
},
|
|
47
|
+
format: realizedTtsFormat(responseFormat)
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
const buildHttpRequest = (cfg, body, accept) => HttpClientRequest.post(`${cfg.baseUrl ?? "https://api.mistral.ai"}/v1/audio/speech`).pipe(HttpClientRequest.bearerToken(cfg.apiKey), HttpClientRequest.accept(accept), HttpClientRequest.bodyJsonUnsafe(body));
|
|
51
|
+
const WireResponse = Schema.Struct({ audio_data: Schema.String });
|
|
52
|
+
const decodeResponse = Schema.decodeUnknownEffect(WireResponse);
|
|
53
|
+
const decodeAudioData = (b64) => Result.match(Encoding.decodeBase64(b64), {
|
|
54
|
+
onSuccess: Effect.succeed,
|
|
55
|
+
onFailure: (cause) => Effect.fail(new AiError.InvalidRequest({
|
|
56
|
+
provider: "mistral",
|
|
57
|
+
param: "audio_data",
|
|
58
|
+
raw: cause
|
|
59
|
+
}))
|
|
60
|
+
});
|
|
61
|
+
const synthesizeImpl = (cfg) => (request) => Effect.gen(function* () {
|
|
62
|
+
const client = yield* HttpClient.HttpClient;
|
|
63
|
+
const { body, format } = yield* buildBody(request);
|
|
64
|
+
const response = yield* client.execute(buildHttpRequest(cfg, body, "application/json")).pipe(Effect.mapError(transportFailure));
|
|
65
|
+
if (response.status >= 400) {
|
|
66
|
+
const text = yield* response.text.pipe(Effect.orElseSucceed(() => ""));
|
|
67
|
+
yield* Effect.logWarning("[voxtral-tts] request failed", {
|
|
68
|
+
status: response.status,
|
|
69
|
+
body: text
|
|
70
|
+
});
|
|
71
|
+
return yield* Effect.fail(httpStatusError(response.status, text));
|
|
72
|
+
}
|
|
73
|
+
const bytes = yield* decodeAudioData((yield* decodeResponse(yield* response.json.pipe(Effect.mapError(transportFailure))).pipe(Effect.mapError(transportFailure))).audio_data);
|
|
74
|
+
yield* Effect.logDebug("[voxtral-tts] ok", {
|
|
75
|
+
bytes: bytes.byteLength,
|
|
76
|
+
voice: request.voiceId
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
format,
|
|
80
|
+
bytes
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
const FRAME_BYTES = 8192;
|
|
84
|
+
const sliceIntoChunks = (bytes) => Array.makeBy(Math.max(1, Math.ceil(bytes.byteLength / FRAME_BYTES)), (i) => ({ bytes: bytes.subarray(i * FRAME_BYTES, (i + 1) * FRAME_BYTES) }));
|
|
85
|
+
const streamSynthesisImpl = (cfg) => (request) => Stream.unwrap(Effect.map(synthesizeImpl(cfg)(request), (blob) => Stream.fromIterable(sliceIntoChunks(blob.bytes))));
|
|
86
|
+
const synthesizeDialogueUnsupported = () => Effect.fail(new AiError.Unsupported({
|
|
87
|
+
provider: "mistral",
|
|
88
|
+
capability: "synthesizeDialogue",
|
|
89
|
+
reason: "Voxtral TTS has no multi-speaker dialogue endpoint."
|
|
90
|
+
}));
|
|
91
|
+
const streamSynthesizeDialogueUnsupported = () => Stream.fail(new AiError.Unsupported({
|
|
92
|
+
provider: "mistral",
|
|
93
|
+
capability: "streamSynthesizeDialogue",
|
|
94
|
+
reason: "Voxtral TTS has no multi-speaker dialogue endpoint."
|
|
95
|
+
}));
|
|
96
|
+
const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => ({
|
|
97
|
+
synthesize: (request) => synthesizeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),
|
|
98
|
+
streamSynthesis: (request) => streamSynthesisImpl(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client)),
|
|
99
|
+
streamSynthesisFrom: (textIn, request) => Stream.unwrap(Effect.map(Stream.runFold(textIn, () => "", (acc, s) => acc + s), (text) => streamSynthesisImpl(cfg)({
|
|
100
|
+
...request,
|
|
101
|
+
text
|
|
102
|
+
}).pipe(Stream.provideService(HttpClient.HttpClient, client)))),
|
|
103
|
+
synthesizeDialogue: synthesizeDialogueUnsupported,
|
|
104
|
+
streamSynthesizeDialogue: streamSynthesizeDialogueUnsupported
|
|
105
|
+
}));
|
|
106
|
+
/**
|
|
107
|
+
* Layer registering `MistralSynthesizer`, the generic `SpeechSynthesizer` tag,
|
|
108
|
+
* and the `TtsIncrementalText` capability marker (so `streamSynthesisFrom`
|
|
109
|
+
* composes — note the text side buffers; see its docs).
|
|
110
|
+
*/
|
|
111
|
+
const layer = (cfg) => Layer.mergeAll(Layer.effect(MistralSynthesizer, make(cfg)), Layer.effect(SpeechSynthesizer, Effect.map(make(cfg), (s) => ({
|
|
112
|
+
synthesize: (req) => s.synthesize(req),
|
|
113
|
+
streamSynthesis: (req) => s.streamSynthesis(req),
|
|
114
|
+
streamSynthesisFrom: s.streamSynthesisFrom,
|
|
115
|
+
synthesizeDialogue: s.synthesizeDialogue,
|
|
116
|
+
streamSynthesizeDialogue: s.streamSynthesizeDialogue
|
|
117
|
+
}))), Layer.succeed(TtsIncrementalText, void 0));
|
|
118
|
+
//#endregion
|
|
119
|
+
export { MistralSynthesizer, layer, make, MistralSynthesizer_exports as t };
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=MistralSynthesizer.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MistralSynthesizer.mjs","names":["Arr"],"sources":["../src/MistralSynthesizer.ts"],"sourcesContent":["import {\n Array as Arr,\n Context,\n Effect,\n Encoding,\n Layer,\n Redacted,\n Result,\n Schema,\n Stream,\n} from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport { containerToTtsFormat, type MistralTtsFormat, realizedTtsFormat } from \"./audioCodec.js\"\nimport { httpStatusError, transportFailure } from \"./http.js\"\nimport type { MistralTtsModel } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Mistral-typed synthesize request. `model` narrows to `MistralTtsModel`;\n * `voiceId` selects a saved Voxtral voice. `refAudio` (base64 of a 2-3s clip)\n * triggers zero-shot voice cloning and takes precedence over `voiceId`.\n */\nexport type MistralSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\"> & {\n readonly model: MistralTtsModel\n readonly refAudio?: string\n}\n\nexport type MistralSynthesizerService = {\n readonly synthesize: (\n request: MistralSynthesizeRequest,\n ) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n request: MistralSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: CommonStreamSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError | E, R>\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class MistralSynthesizer extends Context.Service<\n MistralSynthesizer,\n MistralSynthesizerService\n>()(\"@betalyra/effect-uai/providers/mistral/MistralSynthesizer\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n}\n\n// ---------------------------------------------------------------------------\n// Codec — request → JSON body\n// ---------------------------------------------------------------------------\n\nconst defaultFormat: AudioFormat = { container: \"mp3\", encoding: \"mp3\", sampleRate: 24000 }\n\ntype WireBody = {\n readonly model: string\n readonly input: string\n readonly response_format: MistralTtsFormat\n readonly voice_id?: string\n readonly ref_audio?: string\n}\n\nconst buildBody = (\n request: MistralSynthesizeRequest,\n): Effect.Effect<{ readonly body: WireBody; readonly format: AudioFormat }, AiError.AiError> =>\n Effect.gen(function* () {\n // Voxtral has no phoneme field; pronunciations are load-bearing, so reject\n // rather than silently mispronounce.\n if (request.pronunciations !== undefined && request.pronunciations.length > 0) {\n return yield* Effect.fail(\n new AiError.Unsupported({\n provider: \"mistral\",\n capability: \"pronunciations\",\n reason:\n \"Voxtral TTS has no phoneme field. Use a provider with a phoneme path (Inworld, Google) for pronunciation overrides.\",\n }),\n )\n }\n yield* Capabilities.warnDroppedWhen(request.speed, {\n provider: \"mistral\",\n capability: \"speed\",\n field: \"speed\",\n reason: \"Voxtral TTS has no speed control; prosody follows the voice prompt.\",\n })\n yield* Capabilities.warnDroppedWhen(request.languageCode, {\n provider: \"mistral\",\n capability: \"languageCode\",\n field: \"languageCode\",\n reason: \"Voxtral TTS auto-detects language and clones cross-lingually.\",\n })\n const responseFormat = yield* containerToTtsFormat(\n (request.outputFormat ?? defaultFormat).container,\n )\n return {\n body: {\n model: request.model,\n input: request.text,\n response_format: responseFormat,\n // Cloning clip wins over a saved voice id when both are present.\n ...(request.refAudio !== undefined\n ? { ref_audio: request.refAudio }\n : { voice_id: request.voiceId }),\n },\n format: realizedTtsFormat(responseFormat),\n }\n })\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst buildHttpRequest = (cfg: Config, body: WireBody, accept: string) =>\n HttpClientRequest.post(`${cfg.baseUrl ?? \"https://api.mistral.ai\"}/v1/audio/speech`).pipe(\n HttpClientRequest.bearerToken(cfg.apiKey),\n HttpClientRequest.accept(accept),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n\n// One-shot response: base64 audio. Voxtral's streaming SSE wraps this same\n// payload; since `streamSynthesisFrom` buffers the whole utterance anyway, we\n// drive everything off the simpler one-shot endpoint and slice for pacing.\nconst WireResponse = Schema.Struct({ audio_data: Schema.String })\nconst decodeResponse = Schema.decodeUnknownEffect(WireResponse)\n\nconst decodeAudioData = (b64: string): Effect.Effect<Uint8Array, AiError.AiError> =>\n Result.match(Encoding.decodeBase64(b64), {\n onSuccess: Effect.succeed,\n onFailure: (cause) =>\n Effect.fail(\n new AiError.InvalidRequest({ provider: \"mistral\", param: \"audio_data\", raw: cause }),\n ),\n })\n\nconst synthesizeImpl =\n (cfg: Config) =>\n (\n request: MistralSynthesizeRequest,\n ): Effect.Effect<AudioBlob, AiError.AiError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body, format } = yield* buildBody(request)\n const response = yield* client\n .execute(buildHttpRequest(cfg, body, \"application/json\"))\n .pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n yield* Effect.logWarning(\"[voxtral-tts] request failed\", {\n status: response.status,\n body: text,\n })\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const decoded = yield* decodeResponse(json).pipe(Effect.mapError(transportFailure))\n const bytes = yield* decodeAudioData(decoded.audio_data)\n yield* Effect.logDebug(\"[voxtral-tts] ok\", {\n bytes: bytes.byteLength,\n voice: request.voiceId,\n })\n return { format, bytes }\n })\n\n// ~40 ms frames so the voice loop can pace playback and cut on interrupt.\nconst FRAME_BYTES = 8192\n\nconst sliceIntoChunks = (bytes: Uint8Array): ReadonlyArray<AudioChunk> =>\n Arr.makeBy(Math.max(1, Math.ceil(bytes.byteLength / FRAME_BYTES)), (i) => ({\n bytes: bytes.subarray(i * FRAME_BYTES, (i + 1) * FRAME_BYTES),\n }))\n\nconst streamSynthesisImpl =\n (cfg: Config) =>\n (\n request: MistralSynthesizeRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError, HttpClient.HttpClient> =>\n Stream.unwrap(\n Effect.map(synthesizeImpl(cfg)(request), (blob) =>\n Stream.fromIterable(sliceIntoChunks(blob.bytes)),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// Dialogue — unsupported (Voxtral has no multi-speaker endpoint)\n// ---------------------------------------------------------------------------\n\nconst synthesizeDialogueUnsupported: SpeechSynthesizerService[\"synthesizeDialogue\"] = () =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"mistral\",\n capability: \"synthesizeDialogue\",\n reason: \"Voxtral TTS has no multi-speaker dialogue endpoint.\",\n }),\n )\n\nconst streamSynthesizeDialogueUnsupported: SpeechSynthesizerService[\"streamSynthesizeDialogue\"] =\n () =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"mistral\",\n capability: \"streamSynthesizeDialogue\",\n reason: \"Voxtral TTS has no multi-speaker dialogue endpoint.\",\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<MistralSynthesizerService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient.asEffect(), (client) => ({\n synthesize: (request) =>\n synthesizeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (request) =>\n streamSynthesisImpl(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n // Voxtral has no incremental-text-in WS endpoint, so we fold the text\n // stream into one utterance and hand it to the chunked streaming endpoint.\n // Audio still streams out; only the text side buffers (one turn per call).\n streamSynthesisFrom: (textIn, request) =>\n Stream.unwrap(\n Effect.map(\n Stream.runFold(\n textIn,\n () => \"\",\n (acc, s) => acc + s,\n ),\n (text) =>\n streamSynthesisImpl(cfg)({ ...request, text } as MistralSynthesizeRequest).pipe(\n Stream.provideService(HttpClient.HttpClient, client),\n ),\n ),\n ),\n synthesizeDialogue: synthesizeDialogueUnsupported,\n streamSynthesizeDialogue: streamSynthesizeDialogueUnsupported,\n }))\n\n/**\n * Layer registering `MistralSynthesizer`, the generic `SpeechSynthesizer` tag,\n * and the `TtsIncrementalText` capability marker (so `streamSynthesisFrom`\n * composes — note the text side buffers; see its docs).\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<\n MistralSynthesizer | SpeechSynthesizer | TtsIncrementalText,\n never,\n HttpClient.HttpClient\n> =>\n Layer.mergeAll(\n Layer.effect(MistralSynthesizer, 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 MistralSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as MistralSynthesizeRequest),\n streamSynthesisFrom: s.streamSynthesisFrom,\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n }),\n ),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n )\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { r as MistralTranscribeModel } from "./models-DnDmylpj.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Redacted, Stream } from "effect";
|
|
3
|
+
import { HttpClient } from "effect/unstable/http";
|
|
4
|
+
import * as AiError from "@effect-uai/core/AiError";
|
|
5
|
+
import { CommonStreamTranscribeRequest, CommonTranscribeRequest, Transcriber } from "@effect-uai/core/Transcriber";
|
|
6
|
+
import { TranscriptEvent, TranscriptResult } from "@effect-uai/core/Transcript";
|
|
7
|
+
|
|
8
|
+
//#region src/MistralTranscriber.d.ts
|
|
9
|
+
declare namespace MistralTranscriber_d_exports {
|
|
10
|
+
export { Config, MistralTranscribeRequest, MistralTranscriber, MistralTranscriberService, layer, make, transcribeImpl };
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Mistral-typed transcribe request. `model` narrows to the typed
|
|
14
|
+
* `MistralTranscribeModel` union; `fileName` overrides the multipart upload's
|
|
15
|
+
* filename. Voxtral's batch endpoint supports diarization, word timestamps,
|
|
16
|
+
* and context biasing.
|
|
17
|
+
*/
|
|
18
|
+
type MistralTranscribeRequest = Omit<CommonTranscribeRequest, "model"> & {
|
|
19
|
+
readonly model: MistralTranscribeModel;
|
|
20
|
+
readonly temperature?: number;
|
|
21
|
+
readonly fileName?: string;
|
|
22
|
+
};
|
|
23
|
+
type MistralTranscriberService = {
|
|
24
|
+
readonly transcribe: (request: MistralTranscribeRequest) => Effect.Effect<TranscriptResult, AiError.AiError>;
|
|
25
|
+
readonly streamTranscriptionFrom: <E, R>(audioIn: Stream.Stream<Uint8Array, E, R>, request: CommonStreamTranscribeRequest) => Stream.Stream<TranscriptEvent, AiError.AiError | E, R>;
|
|
26
|
+
};
|
|
27
|
+
declare const MistralTranscriber_base: Context.ServiceClass<MistralTranscriber, "@betalyra/effect-uai/providers/mistral/MistralTranscriber", MistralTranscriberService>;
|
|
28
|
+
declare class MistralTranscriber extends MistralTranscriber_base {}
|
|
29
|
+
type Config = {
|
|
30
|
+
readonly apiKey: Redacted.Redacted;
|
|
31
|
+
readonly baseUrl?: string;
|
|
32
|
+
};
|
|
33
|
+
/** Exported for reuse by `MistralRealtimeTranscriber` (same sync path). */
|
|
34
|
+
declare const transcribeImpl: (cfg: Config) => (request: MistralTranscribeRequest) => Effect.Effect<TranscriptResult, AiError.AiError, HttpClient.HttpClient>;
|
|
35
|
+
declare const make: (cfg: Config) => Effect.Effect<MistralTranscriberService, never, HttpClient.HttpClient>;
|
|
36
|
+
/**
|
|
37
|
+
* Sync-only Layer. Registers `MistralTranscriber` + the generic `Transcriber`
|
|
38
|
+
* tag. Does NOT register `SttStreaming` — for live transcription use
|
|
39
|
+
* `@effect-uai/mistral/MistralRealtimeTranscriber`.
|
|
40
|
+
*/
|
|
41
|
+
declare const layer: (cfg: Config) => Layer.Layer<MistralTranscriber | Transcriber, never, HttpClient.HttpClient>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { Config, MistralTranscribeRequest, MistralTranscriber, MistralTranscriberService, layer, make, MistralTranscriber_d_exports as t, transcribeImpl };
|
|
44
|
+
//# sourceMappingURL=MistralTranscriber.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MistralTranscriber.d.mts","names":[],"sources":["../src/MistralTranscriber.ts"],"mappings":";;;;;;;;;;;;;;;;;KA0BY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,sBAAA;EAAA,SACP,WAAA;EAAA,SACA,QAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GACP,OAAA,EAAS,wBAAA,KACN,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA,CAAQ,OAAA;EAAA,SACpC,uBAAA,SACP,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,CAAA,EAAG,CAAA,GACtC,OAAA,EAAS,6BAAA,KACN,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,OAAA,CAAQ,OAAA,GAAU,CAAA,EAAG,CAAA;AAAA;AAAA,cAC1D,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SACD,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SACjB,OAAA;AAAA;;cA+FE,cAAA,GACV,GAAA,EAAK,MAAA,MAEJ,OAAA,EAAS,wBAAA,KACR,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA,CAAQ,OAAA,EAAS,UAAA,CAAW,UAAA;AAAA,cA6CpD,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;;AAnK9D;;cA+Ka,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,WAAA,SAAoB,UAAA,CAAW,UAAA"}
|