@broberg/ai-sdk 0.24.0 → 0.25.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/README.md +9 -1
- package/dist/index.d.ts +28 -2
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ const emb = await ai.embedding({ text: ["a", "b"] });
|
|
|
30
30
|
|
|
31
31
|
## Capabilities
|
|
32
32
|
|
|
33
|
-
`chat` · `vision` · `translate` · `image` (fal.ai) · `embedding` · `transcribe`
|
|
33
|
+
`chat` · `vision` · `translate` · `image` (fal.ai default / OpenRouter) · `embedding` · `transcribe`
|
|
34
34
|
(Whisper), plus **prompt contracts** with structured output:
|
|
35
35
|
|
|
36
36
|
```ts
|
|
@@ -56,6 +56,14 @@ await ai.chat({ prompt: "…", tier: "powerful" });
|
|
|
56
56
|
await ai.chat({ prompt: "…", override: { provider: "openrouter", model: "minimax/minimax-m2.7" } });
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
> **Images — raster vs. vector.** `ai.image()` defaults to fal.ai (raster PNG). For
|
|
60
|
+
> **vector/SVG** output (logos), override to OpenRouter Recraft — the slug is an
|
|
61
|
+
> **OpenRouter** model, not a fal app-id:
|
|
62
|
+
> ```ts
|
|
63
|
+
> await ai.image({ prompt: "…", override: { provider: "openrouter", model: "recraft/recraft-v4.1-vector" } });
|
|
64
|
+
> // → data:image/svg+xml;base64,… with ground-truth cost
|
|
65
|
+
> ```
|
|
66
|
+
|
|
59
67
|
`cheap` defaults to the cheapest-that's-good-enough cloud model — **Mistral Small**
|
|
60
68
|
(EU/Paris-hosted, GDPR-safe, ~$0.10/$0.30) — so a cost-tier call is safe for
|
|
61
69
|
personal data by default; override per call for an even cheaper non-personal route.
|
package/dist/index.d.ts
CHANGED
|
@@ -239,6 +239,20 @@ interface EmbeddingResult {
|
|
|
239
239
|
vectors: number[][];
|
|
240
240
|
usage: Usage;
|
|
241
241
|
}
|
|
242
|
+
/** Timestamp granularity a caller can request from `ai.transcribe` (F036). */
|
|
243
|
+
type TimestampGranularity = "word" | "segment";
|
|
244
|
+
/** A single word with its start/end offset in seconds. */
|
|
245
|
+
interface WordTimestamp {
|
|
246
|
+
word: string;
|
|
247
|
+
start: number;
|
|
248
|
+
end: number;
|
|
249
|
+
}
|
|
250
|
+
/** A phrase/sentence segment with its start/end offset in seconds. */
|
|
251
|
+
interface SegmentTimestamp {
|
|
252
|
+
text: string;
|
|
253
|
+
start: number;
|
|
254
|
+
end: number;
|
|
255
|
+
}
|
|
242
256
|
interface TranscribeRequest {
|
|
243
257
|
/** Raw audio bytes (the client resolves a URL to bytes before calling). */
|
|
244
258
|
audio: Uint8Array;
|
|
@@ -248,10 +262,17 @@ interface TranscribeRequest {
|
|
|
248
262
|
/** Bias recognition toward these brand/jargon terms (Azure phraseList, F029.3).
|
|
249
263
|
* Providers without biasing support (Voxtral/Whisper) ignore it. */
|
|
250
264
|
phrases?: string[];
|
|
265
|
+
/** Request timestamps (F036). The client normalizes the input to this array.
|
|
266
|
+
* Adapters without timestamp support ignore it (result omits words/segments). */
|
|
267
|
+
timestamps?: TimestampGranularity[];
|
|
251
268
|
spec: TierSpec;
|
|
252
269
|
}
|
|
253
270
|
interface TranscribeResult {
|
|
254
271
|
text: string;
|
|
272
|
+
/** Word-level timing — present only when "word" timestamps were requested. */
|
|
273
|
+
words?: WordTimestamp[];
|
|
274
|
+
/** Segment (phrase/sentence) timing — present when any timestamps were requested. */
|
|
275
|
+
segments?: SegmentTimestamp[];
|
|
255
276
|
usage: Usage;
|
|
256
277
|
}
|
|
257
278
|
interface OcrRequest {
|
|
@@ -1331,6 +1352,9 @@ declare const transcribeInputSchema: z.ZodObject<{
|
|
|
1331
1352
|
durationSec: z.ZodOptional<z.ZodNumber>;
|
|
1332
1353
|
/** Bias toward brand/jargon terms (Azure phraseList, F029.3); others ignore it. */
|
|
1333
1354
|
phrases: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1355
|
+
/** Opt-in timestamps (F036) — a single granularity or an array. Omit → the
|
|
1356
|
+
* current { text, usage } shape, unchanged. Pass ["word","segment"] for both. */
|
|
1357
|
+
timestamps: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["word", "segment"]>, z.ZodArray<z.ZodEnum<["word", "segment"]>, "many">]>>;
|
|
1334
1358
|
}, "strip", z.ZodTypeAny, {
|
|
1335
1359
|
audio: string | Uint8Array<ArrayBuffer>;
|
|
1336
1360
|
language?: string | undefined;
|
|
@@ -1349,6 +1373,7 @@ declare const transcribeInputSchema: z.ZodObject<{
|
|
|
1349
1373
|
labels?: Record<string, string> | undefined;
|
|
1350
1374
|
durationSec?: number | undefined;
|
|
1351
1375
|
phrases?: string[] | undefined;
|
|
1376
|
+
timestamps?: "word" | "segment" | ("word" | "segment")[] | undefined;
|
|
1352
1377
|
}, {
|
|
1353
1378
|
audio: string | Uint8Array<ArrayBuffer>;
|
|
1354
1379
|
language?: string | undefined;
|
|
@@ -1367,6 +1392,7 @@ declare const transcribeInputSchema: z.ZodObject<{
|
|
|
1367
1392
|
labels?: Record<string, string> | undefined;
|
|
1368
1393
|
durationSec?: number | undefined;
|
|
1369
1394
|
phrases?: string[] | undefined;
|
|
1395
|
+
timestamps?: "word" | "segment" | ("word" | "segment")[] | undefined;
|
|
1370
1396
|
}>;
|
|
1371
1397
|
declare const ocrInputSchema: z.ZodObject<{
|
|
1372
1398
|
tier: z.ZodOptional<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>>;
|
|
@@ -2017,8 +2043,8 @@ declare const falStubAdapter: ProviderAdapter;
|
|
|
2017
2043
|
* wires the live adapters. */
|
|
2018
2044
|
declare const stubProviders: Record<string, ProviderAdapter>;
|
|
2019
2045
|
|
|
2020
|
-
declare const VERSION: "0.
|
|
2021
|
-
declare const SDK_TAG: "@broberg/ai-sdk@0.
|
|
2046
|
+
declare const VERSION: "0.25.0";
|
|
2047
|
+
declare const SDK_TAG: "@broberg/ai-sdk@0.25.0";
|
|
2022
2048
|
|
|
2023
2049
|
/** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
|
|
2024
2050
|
* per-call override.
|
package/dist/index.js
CHANGED
|
@@ -730,6 +730,10 @@ function openaiAdapter(config = {}) {
|
|
|
730
730
|
form.append("file", new Blob([req.audio]), "audio");
|
|
731
731
|
form.append("model", req.spec.model);
|
|
732
732
|
if (req.language) form.append("language", req.language);
|
|
733
|
+
if (req.timestamps && req.timestamps.length > 0) {
|
|
734
|
+
form.append("response_format", "verbose_json");
|
|
735
|
+
for (const g of req.timestamps) form.append("timestamp_granularities[]", g);
|
|
736
|
+
}
|
|
733
737
|
const fetchImpl = config.fetch ?? fetch;
|
|
734
738
|
const res = await fetchImpl(`${baseUrl}/audio/transcriptions`, {
|
|
735
739
|
method: "POST",
|
|
@@ -753,7 +757,14 @@ function openaiAdapter(config = {}) {
|
|
|
753
757
|
const perMinute = WHISPER_PRICE_PER_MIN[req.spec.model] ?? 0;
|
|
754
758
|
usage.costUsd = req.durationSec / 60 * perMinute;
|
|
755
759
|
}
|
|
756
|
-
|
|
760
|
+
const result = { text: data.text ?? "", usage };
|
|
761
|
+
if (req.timestamps?.includes("word") && data.words) {
|
|
762
|
+
result.words = data.words.map((w) => ({ word: w.word, start: w.start, end: w.end }));
|
|
763
|
+
}
|
|
764
|
+
if (req.timestamps && req.timestamps.length > 0 && data.segments) {
|
|
765
|
+
result.segments = data.segments.map((s) => ({ text: s.text, start: s.start, end: s.end }));
|
|
766
|
+
}
|
|
767
|
+
return result;
|
|
757
768
|
}
|
|
758
769
|
return { ...base, embedding, transcribe };
|
|
759
770
|
}
|
|
@@ -2526,6 +2537,9 @@ var transcribeInputSchema = z.object({
|
|
|
2526
2537
|
durationSec: z.number().positive().optional(),
|
|
2527
2538
|
/** Bias toward brand/jargon terms (Azure phraseList, F029.3); others ignore it. */
|
|
2528
2539
|
phrases: z.array(z.string()).optional(),
|
|
2540
|
+
/** Opt-in timestamps (F036) — a single granularity or an array. Omit → the
|
|
2541
|
+
* current { text, usage } shape, unchanged. Pass ["word","segment"] for both. */
|
|
2542
|
+
timestamps: z.union([z.enum(["word", "segment"]), z.array(z.enum(["word", "segment"]))]).optional(),
|
|
2529
2543
|
...callOptions
|
|
2530
2544
|
});
|
|
2531
2545
|
var ocrInputSchema = z.object({
|
|
@@ -2572,8 +2586,8 @@ var aiConfigSchema = z.object({
|
|
|
2572
2586
|
});
|
|
2573
2587
|
|
|
2574
2588
|
// src/version.ts
|
|
2575
|
-
var VERSION = "0.
|
|
2576
|
-
var SDK_TAG = "@broberg/ai-sdk@0.
|
|
2589
|
+
var VERSION = "0.25.0";
|
|
2590
|
+
var SDK_TAG = "@broberg/ai-sdk@0.25.0";
|
|
2577
2591
|
|
|
2578
2592
|
// src/cost/sinks/upmetrics.ts
|
|
2579
2593
|
function upmetricsSink(config) {
|
|
@@ -3126,7 +3140,8 @@ function createAI(config = {}) {
|
|
|
3126
3140
|
invoke: async (spec) => {
|
|
3127
3141
|
const adapter = pickProvider(spec.provider);
|
|
3128
3142
|
if (!adapter.transcribe) throw new Error(`createAI: provider "${spec.provider}" does not support transcribe`);
|
|
3129
|
-
|
|
3143
|
+
const timestamps = input.timestamps === void 0 ? void 0 : Array.isArray(input.timestamps) ? input.timestamps : [input.timestamps];
|
|
3144
|
+
return adapter.transcribe({ audio, language: input.language, durationSec: input.durationSec, phrases: input.phrases, timestamps, spec });
|
|
3130
3145
|
}
|
|
3131
3146
|
});
|
|
3132
3147
|
},
|