@wrenautomation/read 0.35.2 → 0.36.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.
@@ -14,6 +14,7 @@ export * from "./store.js";
14
14
  export * from "./tools.js";
15
15
  export * from "./url.js";
16
16
  export * from "./watch.js";
17
+ export * from "./whisper.js";
17
18
  /** What `yt-dlp -J` prints; only what the readers use. */
18
19
  export interface VideoInfo {
19
20
  id: string;
@@ -14,4 +14,5 @@ export * from "./store.js";
14
14
  export * from "./tools.js";
15
15
  export * from "./url.js";
16
16
  export * from "./watch.js";
17
+ export * from "./whisper.js";
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/video/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/video/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Ear } from "@wrenautomation/models/hear";
2
+ import { runFor } from "./tools.js";
3
+ /** Shared with wren studio's word timings. */
4
+ export declare const WHISPER_DIR: string;
5
+ export declare const WHISPER_MODEL: string;
6
+ export interface WhisperOptions {
7
+ bin?: string;
8
+ model?: string;
9
+ /** For tests: a stand-in for the binary. */
10
+ run?: typeof runFor;
11
+ }
12
+ /** The binary runs and the model is on disk. */
13
+ export declare function whisperReady(o?: WhisperOptions): Promise<boolean>;
14
+ /** whisper.cpp as an `Ear`. */
15
+ export declare function whisperSpeech(o?: WhisperOptions): Ear;
16
+ /**
17
+ * The ear for this machine: local whisper when its model is on disk (free, no limit), else Cohere
18
+ * on `cohereKeys` (20 calls a minute and a monthly cap, per org). Undefined: neither.
19
+ */
20
+ export declare function speechHere(cohereKeys: readonly string[]): Ear | undefined;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * A local ear: whisper.cpp (`brew install whisper-cpp`) on this Mac's GPU, large-v3-turbo q5_0.
3
+ * Free, no rate limit, no network. 11-03, 5 real 60 s clips on an M2 Pro: 20 s, 0.9 GB peak, the
4
+ * same words as the full model (1.9 GB). 10-min clips lost half the words; VAD gave none.
5
+ */
6
+ import { existsSync } from "node:fs";
7
+ import { access, mkdtemp, rm, writeFile } from "node:fs/promises";
8
+ import { homedir, tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { runFor, TOOL_MS } from "./tools.js";
11
+ import { cohereSpeech } from "./watch.js";
12
+ /** Shared with wren studio's word timings. */
13
+ export const WHISPER_DIR = join(homedir(), ".cache/wren/whisper");
14
+ export const WHISPER_MODEL = join(WHISPER_DIR, "ggml-large-v3-turbo-q5_0.bin");
15
+ const MODEL_URL = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo-q5_0.bin";
16
+ const EXT = {
17
+ "audio/mpeg": "mp3",
18
+ "audio/wav": "wav",
19
+ "audio/flac": "flac",
20
+ "audio/ogg": "ogg",
21
+ };
22
+ const exists = (f) => access(f).then(() => true, () => false);
23
+ /** The binary runs and the model is on disk. */
24
+ export async function whisperReady(o = {}) {
25
+ if (!(await exists(o.model ?? WHISPER_MODEL)))
26
+ return false;
27
+ return (o.run ?? runFor)(o.bin ?? "whisper-cli", ["--help"], 10_000).then(() => true, () => false);
28
+ }
29
+ /** whisper.cpp as an `Ear`. */
30
+ export function whisperSpeech(o = {}) {
31
+ const bin = o.bin ?? "whisper-cli";
32
+ const model = o.model ?? WHISPER_MODEL;
33
+ const run = o.run ?? runFor;
34
+ return {
35
+ id: "local:whisper-large-v3-turbo",
36
+ model: "whisper-large-v3-turbo",
37
+ async hear(audio, h = {}) {
38
+ if (!(await exists(model)))
39
+ throw new Error(`whisper: no model at ${model}; download ${MODEL_URL}`);
40
+ const dir = await mkdtemp(join(tmpdir(), "whisper-"));
41
+ const started = performance.now();
42
+ try {
43
+ const file = join(dir, `in.${EXT[audio.mediaType] ?? "mp3"}`);
44
+ await writeFile(file, audio.data);
45
+ const { stdout } = await run(bin, [...["-m", model, "-l", h.language ?? "en", "-nt", "-np"], ...["-f", file]], TOOL_MS, { maxBuffer: 32 * 1024 * 1024 });
46
+ const text = stdout
47
+ .split("\n")
48
+ .map((l) => l.trim())
49
+ .filter(Boolean)
50
+ .join(" ");
51
+ return {
52
+ text,
53
+ model: "whisper-large-v3-turbo",
54
+ ms: Math.round(performance.now() - started),
55
+ usd: 0,
56
+ free: true,
57
+ };
58
+ }
59
+ finally {
60
+ await rm(dir, { recursive: true, force: true });
61
+ }
62
+ },
63
+ };
64
+ }
65
+ /**
66
+ * The ear for this machine: local whisper when its model is on disk (free, no limit), else Cohere
67
+ * on `cohereKeys` (20 calls a minute and a monthly cap, per org). Undefined: neither.
68
+ */
69
+ export function speechHere(cohereKeys) {
70
+ if (existsSync(WHISPER_MODEL))
71
+ return whisperSpeech();
72
+ return cohereKeys.length ? cohereSpeech(cohereKeys) : undefined;
73
+ }
74
+ //# sourceMappingURL=whisper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper.js","sourceRoot":"","sources":["../../src/video/whisper.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrenautomation/read",
3
- "version": "0.35.2",
3
+ "version": "0.36.0",
4
4
  "description": "The web and files in, text out. Polite HTTP fetching with robots and a fetch ladder up to a browser; HTML and PDF to text, a page to title, text and links; a video or podcast from a URL or a file (captions, ffmpeg and a vision model, audio to markdown, what a channel or search holds); a study's synthesis reader whose every claim quotes a page.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -49,7 +49,7 @@
49
49
  "robots-parser": "3.0.1",
50
50
  "unpdf": "1.8.1",
51
51
  "zod": "4.6.5",
52
- "@wrenautomation/models": "0.35.2"
52
+ "@wrenautomation/models": "0.36.0"
53
53
  },
54
54
  "scripts": {
55
55
  "typecheck": "tsc --noEmit",