@wrenautomation/falcon 0.0.0-stage → 0.3.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.md +91 -0
- package/README.md +50 -2
- package/dist/app/cli.d.ts +2 -0
- package/dist/app/cli.js +77 -0
- package/dist/app/cli.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/study/claims.d.ts +50 -0
- package/dist/study/claims.js +123 -0
- package/dist/study/claims.js.map +1 -0
- package/dist/study/drafts.d.ts +43 -0
- package/dist/study/drafts.js +93 -0
- package/dist/study/drafts.js.map +1 -0
- package/dist/study/evidence.d.ts +31 -0
- package/dist/study/evidence.js +123 -0
- package/dist/study/evidence.js.map +1 -0
- package/dist/study/grounding.d.ts +29 -0
- package/dist/study/grounding.js +58 -0
- package/dist/study/grounding.js.map +1 -0
- package/dist/study/index.d.ts +10 -0
- package/dist/study/index.js +11 -0
- package/dist/study/index.js.map +1 -0
- package/dist/study/report.d.ts +55 -0
- package/dist/study/report.js +56 -0
- package/dist/study/report.js.map +1 -0
- package/dist/text/entities.d.ts +2 -0
- package/dist/text/entities.js +4 -0
- package/dist/text/entities.js.map +1 -0
- package/dist/text/htmltext.d.ts +30 -0
- package/dist/text/htmltext.js +208 -0
- package/dist/text/htmltext.js.map +1 -0
- package/dist/text/index.d.ts +7 -0
- package/dist/text/index.js +8 -0
- package/dist/text/index.js.map +1 -0
- package/dist/text/text.d.ts +8 -0
- package/dist/text/text.js +38 -0
- package/dist/text/text.js.map +1 -0
- package/dist/video/gemini.d.ts +35 -0
- package/dist/video/gemini.js +103 -0
- package/dist/video/gemini.js.map +1 -0
- package/dist/video/index.d.ts +34 -0
- package/dist/video/index.js +11 -0
- package/dist/video/index.js.map +1 -0
- package/dist/video/read.d.ts +52 -0
- package/dist/video/read.js +99 -0
- package/dist/video/read.js.map +1 -0
- package/dist/video/shots.d.ts +33 -0
- package/dist/video/shots.js +151 -0
- package/dist/video/shots.js.map +1 -0
- package/dist/video/tools.d.ts +16 -0
- package/dist/video/tools.js +29 -0
- package/dist/video/tools.js.map +1 -0
- package/dist/video/watch.d.ts +101 -0
- package/dist/video/watch.js +420 -0
- package/dist/video/watch.js.map +1 -0
- package/package.json +66 -4
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the source readers share: a child tool run with a time limit, and the clock mark.
|
|
3
|
+
* Own file so `watch.ts` and any other reader import the same one.
|
|
4
|
+
*/
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
6
|
+
import { basename } from "node:path";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
export const run = promisify(execFile);
|
|
9
|
+
/** yt-dlp's metadata call, or a download and remux of a reel, past this is stuck. */
|
|
10
|
+
export const TOOL_MS = 300_000;
|
|
11
|
+
/** Run a tool; past `ms` it is killed and the error says which tool and how long. */
|
|
12
|
+
export async function runFor(cmd, args, ms, opts = {}) {
|
|
13
|
+
try {
|
|
14
|
+
return await run(cmd, args, { ...opts, timeout: ms, killSignal: "SIGKILL" });
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
if (err.killed)
|
|
18
|
+
throw new Error(`${basename(cmd)} timed out after ${Math.round(ms / 1000)}s`);
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const clock = (s) => {
|
|
23
|
+
const h = Math.floor(s / 3600);
|
|
24
|
+
const m = Math.floor((s % 3600) / 60);
|
|
25
|
+
const sec = Math.floor(s % 60);
|
|
26
|
+
const mm = `${m}:${String(sec).padStart(2, "0")}`;
|
|
27
|
+
return h ? `${h}:${String(m).padStart(2, "0")}:${String(sec).padStart(2, "0")}` : mm;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/video/tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEvC,qFAAqF;AACrF,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,GAAW,EACX,IAAc,EACd,EAAU,EACV,OAA+B,EAAE;IAEjC,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA4B,CAAC,MAAM;YACtC,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAChF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE;IACzC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IAClD,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACvF,CAAC,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export declare const COHERE_VISION_MODEL = "command-a-vision-07-2025";
|
|
2
|
+
/** The text model for asks that need no picture (`video look --with cohere`). */
|
|
3
|
+
/** Cohere's text model on its OpenAI-compatible route. */
|
|
4
|
+
export declare const COHERE_TEXT_MODEL = "command-a-03-2025";
|
|
5
|
+
export interface Frame {
|
|
6
|
+
/** Seconds into the video, from the ffmpeg frame grid. */
|
|
7
|
+
at: number;
|
|
8
|
+
text: string | null;
|
|
9
|
+
}
|
|
10
|
+
/** PySceneDetect's detectors: `hash` is the one films trust, `adaptive` the second signal. */
|
|
11
|
+
export declare const SCENE_DETECTORS: readonly ["hash", "adaptive"];
|
|
12
|
+
export type SceneDetector = (typeof SCENE_DETECTORS)[number];
|
|
13
|
+
export interface Watched {
|
|
14
|
+
durationS: number;
|
|
15
|
+
/** Scene cuts ffmpeg found, in seconds. */
|
|
16
|
+
cuts: number[];
|
|
17
|
+
/** PySceneDetect's cuts by detector; only with `sceneDetect`. */
|
|
18
|
+
cutsBy?: Record<SceneDetector, number[]>;
|
|
19
|
+
/** Whether the file has a sound track at all. */
|
|
20
|
+
audio: boolean;
|
|
21
|
+
/** What Cohere heard; "" when nobody speaks or speech was not asked for. */
|
|
22
|
+
speech: string;
|
|
23
|
+
frames: Frame[];
|
|
24
|
+
/** Gemini's read of the screen, when a key worked. */
|
|
25
|
+
gemini?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface WatchOptions {
|
|
28
|
+
cohereKeys: readonly string[];
|
|
29
|
+
/** Optional: their read of the screen is added when one still works. */
|
|
30
|
+
geminiKeys?: readonly string[];
|
|
31
|
+
ffmpeg?: string;
|
|
32
|
+
/** The PySceneDetect command (split on spaces: `uvx scenedetect`); set, its cuts come too (`cutsBy`). */
|
|
33
|
+
sceneDetect?: string;
|
|
34
|
+
fetchFn?: typeof fetch;
|
|
35
|
+
/** False: skip the transcription (the caller has the words already). */
|
|
36
|
+
speech?: boolean;
|
|
37
|
+
/** ISO 639-1 code of the spoken language. */
|
|
38
|
+
language?: string;
|
|
39
|
+
/** Seconds between frames; stretched so a long video stays under `MAX_FRAMES`. */
|
|
40
|
+
everyS?: number;
|
|
41
|
+
/** For tests: stands in for the wait between retries. */
|
|
42
|
+
pause?: (ms: number) => Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
type Pause = (ms: number) => Promise<void>;
|
|
45
|
+
/** `0:03.2`, a mark with a tenth of a second. */
|
|
46
|
+
export declare function stamp(s: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* One Cohere call (JSON body or a multipart `FormData`). A bad key (401/403), a limit (429) or a
|
|
49
|
+
* busy server hands the call to the next key, waiting 2 s doubling to 30 s on the last two; any
|
|
50
|
+
* other refusal throws at once. The key goes in a header and never into an error.
|
|
51
|
+
*/
|
|
52
|
+
export declare function cohereCall<T>(keys: readonly string[], path: string, body: object | FormData, o?: {
|
|
53
|
+
fetchFn?: typeof fetch;
|
|
54
|
+
pause?: Pause;
|
|
55
|
+
label?: string;
|
|
56
|
+
}): Promise<T>;
|
|
57
|
+
/** A chat answer's text. */
|
|
58
|
+
export declare function cohereChat(keys: readonly string[], body: object, o?: Parameters<typeof cohereCall>[3]): Promise<string>;
|
|
59
|
+
type Shot = {
|
|
60
|
+
at: number;
|
|
61
|
+
jpeg: Buffer;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* On-screen text for each frame, `BATCH` frames a call, `BATCHES_AT_ONCE` calls at a time. A
|
|
65
|
+
* batch that cannot be asked at all leaves its frames unread (and a warning); all of them
|
|
66
|
+
* failing throws.
|
|
67
|
+
*/
|
|
68
|
+
export declare function readScreen(shots: Shot[], keys: readonly string[], o?: {
|
|
69
|
+
fetchFn?: typeof fetch;
|
|
70
|
+
pause?: Pause;
|
|
71
|
+
}): Promise<Frame[]>;
|
|
72
|
+
/** Cut times from a `list-scenes` CSV (`--skip-cuts`: the header, then one row a scene). Each scene after the first starts on a cut. */
|
|
73
|
+
export declare function parseScenes(csv: string): number[];
|
|
74
|
+
/** PySceneDetect's cuts by one detector. ffmpeg's `scene` misses a fade and a card swap on black; `hash` finds them (designs/studies/2026-10-25-launch-films.md). */
|
|
75
|
+
export declare function sceneDetectCuts(file: string, detector: SceneDetector, cmd: string, dir: string): Promise<number[]>;
|
|
76
|
+
/** Shot changes: the frames `select` keeps are logged by `showinfo`, on stderr. */
|
|
77
|
+
export declare function sceneCuts(file: string, ffmpeg: string): Promise<number[]>;
|
|
78
|
+
/** Watch a video file on disk (a URL is fetched first by weaver's `watch`). */
|
|
79
|
+
export declare function watch(input: string, opts: WatchOptions): Promise<Watched>;
|
|
80
|
+
/** The frames with something to say, each under its ffmpeg frame time; the unread ones say so. */
|
|
81
|
+
export declare function onScreenLines(w: Pick<Watched, "frames">): string[];
|
|
82
|
+
export declare const cutsLine: (w: Pick<Watched, "cuts">) => string;
|
|
83
|
+
/** `read`, `unread`: how many frames the model returned a line for. */
|
|
84
|
+
export declare function frameCounts(w: Pick<Watched, "frames">): {
|
|
85
|
+
read: number;
|
|
86
|
+
unread: number;
|
|
87
|
+
};
|
|
88
|
+
/** The `## Speech`, `## On screen` and `## Cuts` sections; the CLI prints it and a SOP source holds it. */
|
|
89
|
+
/** What a film's facts are read from later: the length, the sound track, every detector's cuts. */
|
|
90
|
+
export interface WatchFacts {
|
|
91
|
+
duration_s: number;
|
|
92
|
+
audio: boolean;
|
|
93
|
+
cuts_by: {
|
|
94
|
+
ffmpeg: number[];
|
|
95
|
+
} & Partial<Record<SceneDetector, number[]>>;
|
|
96
|
+
}
|
|
97
|
+
export declare const watchFacts: (w: Pick<Watched, "durationS" | "audio" | "cuts" | "cutsBy">) => WatchFacts;
|
|
98
|
+
/** The facts fence of a rendered page, when it has one. */
|
|
99
|
+
export declare function readWatchFacts(md: string): WatchFacts | null;
|
|
100
|
+
export declare function renderWatched(w: Watched): string;
|
|
101
|
+
export {};
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watching a video (designs/2026-10-21-video-watch.md). ffmpeg gives the facts: length,
|
|
3
|
+
* scene cuts, one 360p frame every 2 s, the speech as a small mono mp3. Cohere reads them: the
|
|
4
|
+
* speech with Transcribe, the on-screen text with command-a-vision. Gemini adds its own read of
|
|
5
|
+
* the screen only when a key still works. One core; every caller passes its own keys and tools.
|
|
6
|
+
* Nothing here touches a database.
|
|
7
|
+
*
|
|
8
|
+
* Cohere's vision is weak, so the result keeps what it did not read: a frame with no line is
|
|
9
|
+
* `null`, never filled from its neighbours, and every line carries its ffmpeg frame time.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdir, mkdtemp, readdir, readFile, rm } from "node:fs/promises";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { join, resolve } from "node:path";
|
|
14
|
+
import { askShown, INLINE_MAX, SHOWN, shrink } from "./gemini.js";
|
|
15
|
+
import { clock, runFor, TOOL_MS } from "./tools.js";
|
|
16
|
+
const COHERE = "https://api.cohere.com";
|
|
17
|
+
const COHERE_SPEECH_MODEL = "cohere-transcribe-03-2026";
|
|
18
|
+
export const COHERE_VISION_MODEL = "command-a-vision-07-2025";
|
|
19
|
+
/** The text model for asks that need no picture (`video look --with cohere`). */
|
|
20
|
+
/** Cohere's text model on its OpenAI-compatible route. */
|
|
21
|
+
export const COHERE_TEXT_MODEL = "command-a-03-2025";
|
|
22
|
+
/** Cohere takes 25 MB of audio a call; at 48 kbps that is about 70 minutes. */
|
|
23
|
+
const COHERE_FILE_MAX = 25_000_000;
|
|
24
|
+
const COHERE_CALL_MS = 120_000;
|
|
25
|
+
/** Frames per vision call. */
|
|
26
|
+
const BATCH = 8;
|
|
27
|
+
/** Vision calls at one time; trial keys allow about 20 calls a minute. */
|
|
28
|
+
const BATCHES_AT_ONCE = 3;
|
|
29
|
+
/** ffmpeg's scene score above which a frame starts a new shot. */
|
|
30
|
+
const SCENE = 0.25;
|
|
31
|
+
const FRAME_EVERY_S = 2;
|
|
32
|
+
/** A longer video gets its frames further apart, not more of them. */
|
|
33
|
+
const MAX_FRAMES = 300;
|
|
34
|
+
/** PySceneDetect's detectors: `hash` is the one films trust, `adaptive` the second signal. */
|
|
35
|
+
export const SCENE_DETECTORS = ["hash", "adaptive"];
|
|
36
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
37
|
+
/** `0:03.2`, a mark with a tenth of a second. */
|
|
38
|
+
export function stamp(s) {
|
|
39
|
+
const t = Math.round(s * 10);
|
|
40
|
+
return `${clock(Math.floor(t / 10))}.${t % 10}`;
|
|
41
|
+
}
|
|
42
|
+
let nextCohere = 0;
|
|
43
|
+
/** Keys rotate on these; the rest of the 4xx are our mistake and stop the call. */
|
|
44
|
+
const RETRY = new Set([401, 403, 429, 500, 502, 503, 504]);
|
|
45
|
+
/**
|
|
46
|
+
* One Cohere call (JSON body or a multipart `FormData`). A bad key (401/403), a limit (429) or a
|
|
47
|
+
* busy server hands the call to the next key, waiting 2 s doubling to 30 s on the last two; any
|
|
48
|
+
* other refusal throws at once. The key goes in a header and never into an error.
|
|
49
|
+
*/
|
|
50
|
+
export async function cohereCall(keys, path, body, o = {}) {
|
|
51
|
+
const label = o.label ?? path;
|
|
52
|
+
if (!keys.length)
|
|
53
|
+
throw new Error(`cohere ${label}: no COHERE keys`);
|
|
54
|
+
const fetchFn = o.fetchFn ?? fetch;
|
|
55
|
+
const pause = o.pause ?? sleep;
|
|
56
|
+
const form = body instanceof FormData;
|
|
57
|
+
let last = "";
|
|
58
|
+
let wait = 2000;
|
|
59
|
+
for (let i = 0; i < Math.max(3, keys.length * 2); i++) {
|
|
60
|
+
const key = keys[nextCohere++ % keys.length];
|
|
61
|
+
let res;
|
|
62
|
+
try {
|
|
63
|
+
res = await fetchFn(`${COHERE}${path}`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: {
|
|
66
|
+
authorization: `Bearer ${key}`,
|
|
67
|
+
...(form ? {} : { "content-type": "application/json" }),
|
|
68
|
+
},
|
|
69
|
+
body: form ? body : JSON.stringify(body),
|
|
70
|
+
signal: AbortSignal.timeout(COHERE_CALL_MS),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
last = err instanceof Error ? err.message : String(err);
|
|
75
|
+
await pause(wait);
|
|
76
|
+
wait = Math.min(wait * 2, 30_000);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const text = await res.text();
|
|
80
|
+
if (res.ok) {
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(text);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
throw new Error(`cohere ${label}: answered ${text.slice(0, 80)}, not JSON`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
last = `HTTP ${res.status} ${text.slice(0, 200)}`;
|
|
89
|
+
if (!RETRY.has(res.status))
|
|
90
|
+
throw new Error(`cohere ${label}: ${last}`);
|
|
91
|
+
if (res.status !== 401 && res.status !== 403) {
|
|
92
|
+
await pause(wait);
|
|
93
|
+
wait = Math.min(wait * 2, 30_000);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`cohere ${label}: every try refused, last ${last}`);
|
|
97
|
+
}
|
|
98
|
+
/** A chat answer's text. */
|
|
99
|
+
export async function cohereChat(keys, body, o = {}) {
|
|
100
|
+
const r = await cohereCall(keys, "/v2/chat", body, { label: "chat", ...o });
|
|
101
|
+
return (r.message?.content ?? [])
|
|
102
|
+
.map((c) => c.text ?? "")
|
|
103
|
+
.join("")
|
|
104
|
+
.trim();
|
|
105
|
+
}
|
|
106
|
+
// -- the screen ---------------------------------------------------------------------------
|
|
107
|
+
const SCREEN_ASK = (times) => `These are ${times.length} frames from one video, in order. Their times: ${times.join(", ")}. Read the text shown in each frame: captions, titles, slide and UI text, labels, numbers. Reply with exactly one line per frame, starting with its time in square brackets, like "[${times[0]}] text". Write "[${times[0]}] none" for a frame with no text. No other text.`;
|
|
108
|
+
/** Added to the ask once, when the model would not describe a frame. */
|
|
109
|
+
const TEXT_ONLY = "Read only on-screen text, UI and graphics. Ignore people.";
|
|
110
|
+
/** The model declining ("I can't assist with describing images of people"), as opposed to reading. */
|
|
111
|
+
const REFUSAL = /\bi(?:'|’)?m (?:sorry|unable|not able)|\bi am (?:sorry|unable|not able)|\bunable to (?:assist|help|describe|identify|process|provide|analy[sz]e)|\b(?:can(?:'|’)?t|cannot|can not|won(?:'|’)?t|not able to)\s+(?:\w+\s+){0,3}(?:assist|help|describe|identify|process|provide|analy[sz]e|comply)/i;
|
|
112
|
+
const LINE = /^[\s*•-]*\[?(\d+(?::\d{2}){1,2})\]?\s*[:–—-]?\s*(.*)$/;
|
|
113
|
+
const NONE = /^(?:none|no text|n\/a|-)\.?$/i;
|
|
114
|
+
/**
|
|
115
|
+
* The lines of an answer by frame time. A time that is not in the batch is dropped; the first
|
|
116
|
+
* line for a time wins; a refusing line is dropped. `refused`: the model declined, in a line or
|
|
117
|
+
* as the whole answer.
|
|
118
|
+
*/
|
|
119
|
+
function parseScreen(answer, times) {
|
|
120
|
+
const lines = new Map();
|
|
121
|
+
let refused = false;
|
|
122
|
+
for (const raw of answer.split("\n")) {
|
|
123
|
+
const m = LINE.exec(raw);
|
|
124
|
+
if (!m || !times.has(m[1]) || lines.has(m[1]))
|
|
125
|
+
continue;
|
|
126
|
+
const text = (m[2] ?? "").trim();
|
|
127
|
+
if (REFUSAL.test(text.slice(0, 80)))
|
|
128
|
+
refused = true;
|
|
129
|
+
else
|
|
130
|
+
lines.set(m[1], NONE.test(text) ? "" : text);
|
|
131
|
+
}
|
|
132
|
+
if (!lines.size && REFUSAL.test(answer))
|
|
133
|
+
refused = true;
|
|
134
|
+
return { lines, refused };
|
|
135
|
+
}
|
|
136
|
+
async function readBatch(batch, keys, o) {
|
|
137
|
+
const times = batch.map((f) => clock(f.at));
|
|
138
|
+
const ask = (extra) => cohereChat(keys, {
|
|
139
|
+
model: COHERE_VISION_MODEL,
|
|
140
|
+
messages: [
|
|
141
|
+
{
|
|
142
|
+
role: "user",
|
|
143
|
+
content: [
|
|
144
|
+
{ type: "text", text: `${SCREEN_ASK(times)}${extra}` },
|
|
145
|
+
...batch.map((f) => ({
|
|
146
|
+
type: "image_url",
|
|
147
|
+
image_url: { url: `data:image/jpeg;base64,${f.jpeg.toString("base64")}` },
|
|
148
|
+
})),
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
}, { ...o, label: `vision ${times[0]}` });
|
|
153
|
+
const first = parseScreen(await ask(""), new Set(times));
|
|
154
|
+
if (first.refused) {
|
|
155
|
+
// Once more, told to leave people out. A frame the first answer read keeps its line.
|
|
156
|
+
const again = parseScreen(await ask(` ${TEXT_ONLY}`), new Set(times));
|
|
157
|
+
for (const [t, text] of again.lines)
|
|
158
|
+
if (!first.lines.has(t))
|
|
159
|
+
first.lines.set(t, text);
|
|
160
|
+
}
|
|
161
|
+
// A time with no line stays null: not read. Never filled from the frames around it.
|
|
162
|
+
return batch.map((f, i) => ({ at: f.at, text: first.lines.get(times[i]) ?? null }));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* On-screen text for each frame, `BATCH` frames a call, `BATCHES_AT_ONCE` calls at a time. A
|
|
166
|
+
* batch that cannot be asked at all leaves its frames unread (and a warning); all of them
|
|
167
|
+
* failing throws.
|
|
168
|
+
*/
|
|
169
|
+
export async function readScreen(shots, keys, o = {}) {
|
|
170
|
+
const batches = [];
|
|
171
|
+
for (let i = 0; i < shots.length; i += BATCH)
|
|
172
|
+
batches.push(shots.slice(i, i + BATCH));
|
|
173
|
+
const out = [];
|
|
174
|
+
const errors = [];
|
|
175
|
+
for (let i = 0; i < batches.length; i += BATCHES_AT_ONCE) {
|
|
176
|
+
const group = batches.slice(i, i + BATCHES_AT_ONCE);
|
|
177
|
+
const done = await Promise.allSettled(group.map((b) => readBatch(b, keys, o)));
|
|
178
|
+
for (const [j, r] of done.entries()) {
|
|
179
|
+
if (r.status === "fulfilled") {
|
|
180
|
+
out.push(...r.value);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const err = r.reason instanceof Error ? r.reason : new Error(String(r.reason));
|
|
184
|
+
errors.push(err);
|
|
185
|
+
console.warn(`${err.message}; frames from ${clock(group[j]?.[0]?.at ?? 0)} not read`);
|
|
186
|
+
out.push(...(group[j] ?? []).map((f) => ({ at: f.at, text: null })));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (batches.length && errors.length === batches.length)
|
|
190
|
+
throw errors[0];
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
async function probe(file, ffmpeg) {
|
|
194
|
+
const { stdout } = await runFor(ffmpeg.replace(/ffmpeg$/, "ffprobe"), [
|
|
195
|
+
...["-v", "error", "-of", "json", file],
|
|
196
|
+
...["-show_entries", "format=duration:stream=codec_type,width,height"],
|
|
197
|
+
], TOOL_MS);
|
|
198
|
+
const j = JSON.parse(stdout);
|
|
199
|
+
const picture = (j.streams ?? []).find((s) => s.codec_type === "video");
|
|
200
|
+
return {
|
|
201
|
+
durationS: Number(j.format?.duration) || 0,
|
|
202
|
+
audio: (j.streams ?? []).some((s) => s.codec_type === "audio"),
|
|
203
|
+
picture: !!picture,
|
|
204
|
+
...(picture?.width ? { width: picture.width } : {}),
|
|
205
|
+
...(picture?.height ? { height: picture.height } : {}),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** Frame `i` (from 0) is at `i * every`. Short side 360, so a wide screen recording stays readable. */
|
|
209
|
+
async function frames(file, dir, every, ffmpeg) {
|
|
210
|
+
const out = join(dir, "frames");
|
|
211
|
+
await mkdir(out);
|
|
212
|
+
const scale = "scale='if(gt(iw,ih),-2,360)':'if(gt(iw,ih),360,-2)'";
|
|
213
|
+
await runFor(ffmpeg, [
|
|
214
|
+
...["-hide_banner", "-loglevel", "error", "-i", file, "-an"],
|
|
215
|
+
...["-vf", `fps=1/${every},${scale}`, "-q:v", "5", join(out, "%03d.jpg")],
|
|
216
|
+
], TOOL_MS);
|
|
217
|
+
const names = (await readdir(out)).filter((n) => n.endsWith(".jpg")).sort();
|
|
218
|
+
return Promise.all(names.map(async (n, i) => ({ at: i * every, jpeg: await readFile(join(out, n)) })));
|
|
219
|
+
}
|
|
220
|
+
/** Cut times from a `list-scenes` CSV (`--skip-cuts`: the header, then one row a scene). Each scene after the first starts on a cut. */
|
|
221
|
+
export function parseScenes(csv) {
|
|
222
|
+
const rows = csv.trim().split("\n");
|
|
223
|
+
const col = (rows[0] ?? "").split(",").indexOf("Start Time (seconds)");
|
|
224
|
+
if (col < 0)
|
|
225
|
+
return [];
|
|
226
|
+
return rows
|
|
227
|
+
.slice(2)
|
|
228
|
+
.map((r) => Math.round(Number(r.split(",")[col]) * 100) / 100)
|
|
229
|
+
.filter((n) => Number.isFinite(n));
|
|
230
|
+
}
|
|
231
|
+
/** PySceneDetect's cuts by one detector. ffmpeg's `scene` misses a fade and a card swap on black; `hash` finds them (designs/studies/2026-10-25-launch-films.md). */
|
|
232
|
+
export async function sceneDetectCuts(file, detector, cmd, dir) {
|
|
233
|
+
const [bin, ...pre] = cmd.split(/\s+/);
|
|
234
|
+
const name = `scenes-${detector}.csv`;
|
|
235
|
+
await runFor(bin, [
|
|
236
|
+
...pre,
|
|
237
|
+
"-q",
|
|
238
|
+
"-i",
|
|
239
|
+
file,
|
|
240
|
+
`detect-${detector}`,
|
|
241
|
+
"list-scenes",
|
|
242
|
+
"-o",
|
|
243
|
+
dir,
|
|
244
|
+
"-f",
|
|
245
|
+
name,
|
|
246
|
+
"--skip-cuts",
|
|
247
|
+
], TOOL_MS);
|
|
248
|
+
return parseScenes(await readFile(join(dir, name), "utf8"));
|
|
249
|
+
}
|
|
250
|
+
/** Shot changes: the frames `select` keeps are logged by `showinfo`, on stderr. */
|
|
251
|
+
export async function sceneCuts(file, ffmpeg) {
|
|
252
|
+
const { stderr } = await runFor(ffmpeg, [
|
|
253
|
+
...["-hide_banner", "-nostats", "-i", file, "-an"],
|
|
254
|
+
...["-vf", `select='gt(scene,${SCENE})',showinfo`, "-f", "null", "-"],
|
|
255
|
+
], TOOL_MS, { maxBuffer: 64 * 1024 * 1024 });
|
|
256
|
+
return [...stderr.matchAll(/pts_time:(\d+(?:\.\d+)?)/g)].map((m) => Math.round(Number(m[1]) * 100) / 100);
|
|
257
|
+
}
|
|
258
|
+
async function speech(file, dir, ffmpeg, keys, o) {
|
|
259
|
+
const mp3 = join(dir, "speech.mp3");
|
|
260
|
+
await runFor(ffmpeg, [
|
|
261
|
+
...["-hide_banner", "-loglevel", "error", "-y", "-i", file, "-vn"],
|
|
262
|
+
...["-ac", "1", "-ar", "16000", "-b:a", "48k", mp3],
|
|
263
|
+
], TOOL_MS);
|
|
264
|
+
const bytes = await readFile(mp3);
|
|
265
|
+
if (bytes.length > COHERE_FILE_MAX)
|
|
266
|
+
throw new Error(`speech: ${(bytes.length / 1e6).toFixed(1)} MB of audio, over Cohere's ${COHERE_FILE_MAX / 1e6} MB`);
|
|
267
|
+
const form = new FormData();
|
|
268
|
+
form.set("model", COHERE_SPEECH_MODEL);
|
|
269
|
+
form.set("language", o.language);
|
|
270
|
+
form.set("file", new Blob([bytes], { type: "audio/mpeg" }), "speech.mp3");
|
|
271
|
+
const r = await cohereCall(keys, "/v2/audio/transcriptions", form, {
|
|
272
|
+
...o,
|
|
273
|
+
label: "transcribe",
|
|
274
|
+
});
|
|
275
|
+
return (r.text ?? "").trim();
|
|
276
|
+
}
|
|
277
|
+
// -- Gemini, when it works ---------------------------------------------------------------
|
|
278
|
+
const GEMINI_KEY_CHECK = "https://generativelanguage.googleapis.com/v1beta/models?pageSize=1";
|
|
279
|
+
/** The keys the API still accepts; a revoked fleet gives none, quickly. */
|
|
280
|
+
async function liveGeminiKeys(keys, fetchFn) {
|
|
281
|
+
const ok = await Promise.all(keys.map((key) => fetchFn(GEMINI_KEY_CHECK, {
|
|
282
|
+
headers: { "x-goog-api-key": key },
|
|
283
|
+
signal: AbortSignal.timeout(15_000),
|
|
284
|
+
}).then((r) => r.ok, () => false)));
|
|
285
|
+
return keys.filter((_, i) => ok[i]);
|
|
286
|
+
}
|
|
287
|
+
/** Gemini's read of the screen from the video inline, as the SOP reader did before Cohere. Undefined: no key worked, or nothing came back. */
|
|
288
|
+
async function geminiScreen(file, dir, keys, o) {
|
|
289
|
+
const live = await liveGeminiKeys(keys, o.fetchFn);
|
|
290
|
+
if (!live.length)
|
|
291
|
+
return undefined;
|
|
292
|
+
let bytes = await readFile(file);
|
|
293
|
+
if (bytes.length > INLINE_MAX)
|
|
294
|
+
bytes = await shrink(file, join(dir, "small.mp4"), o.info, o.ffmpeg);
|
|
295
|
+
if (bytes.length > INLINE_MAX)
|
|
296
|
+
return undefined;
|
|
297
|
+
const video = { inlineData: { mimeType: "video/mp4", data: bytes.toString("base64") } };
|
|
298
|
+
const r = await askShown((paraphrase) => ({
|
|
299
|
+
contents: [
|
|
300
|
+
{
|
|
301
|
+
parts: [
|
|
302
|
+
video,
|
|
303
|
+
{
|
|
304
|
+
text: `${SHOWN(0, paraphrase)} Markdown. If nothing is shown, reply with the single word none.`,
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
}), live, o.fetchFn, "watch screen");
|
|
310
|
+
if ("unread" in r) {
|
|
311
|
+
console.warn(`gemini watch screen: unread, last ${r.unread}`);
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
return r.text.toLowerCase() === "none" ? undefined : r.text;
|
|
315
|
+
}
|
|
316
|
+
// -- the core -----------------------------------------------------------------------------
|
|
317
|
+
/** `Promise.all` that lets every promise finish before it throws the first failure: nothing still writes into the work directory when it goes. */
|
|
318
|
+
async function allSettled(ps) {
|
|
319
|
+
const done = await Promise.allSettled(ps);
|
|
320
|
+
for (const r of done)
|
|
321
|
+
if (r.status === "rejected")
|
|
322
|
+
throw r.reason;
|
|
323
|
+
return done.map((r) => r.value);
|
|
324
|
+
}
|
|
325
|
+
/** Watch a video file on disk (a URL is fetched first by weaver's `watch`). */
|
|
326
|
+
export async function watch(input, opts) {
|
|
327
|
+
if (!opts.cohereKeys.length)
|
|
328
|
+
throw new Error(`${input}: needs COHERE keys to read the speech and the screen`);
|
|
329
|
+
const ffmpeg = opts.ffmpeg ?? "ffmpeg";
|
|
330
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
331
|
+
const dir = await mkdtemp(join(tmpdir(), "watch-"));
|
|
332
|
+
try {
|
|
333
|
+
const file = resolve(input);
|
|
334
|
+
const facts = await probe(file, ffmpeg).catch((err) => {
|
|
335
|
+
throw new Error(`${input}: ffprobe could not read it (${err.message.split("\n")[0]})`);
|
|
336
|
+
});
|
|
337
|
+
if (!facts.picture)
|
|
338
|
+
throw new Error(`${input}: no picture to watch`);
|
|
339
|
+
const durationS = facts.durationS;
|
|
340
|
+
const every = Math.max(opts.everyS ?? FRAME_EVERY_S, Math.ceil(durationS / MAX_FRAMES));
|
|
341
|
+
const call = { fetchFn, ...(opts.pause ? { pause: opts.pause } : {}) };
|
|
342
|
+
const psd = async (d) => opts.sceneDetect ? sceneDetectCuts(file, d, opts.sceneDetect, dir) : [];
|
|
343
|
+
const [c, h, a, f, s, g] = await allSettled([
|
|
344
|
+
sceneCuts(file, ffmpeg),
|
|
345
|
+
psd("hash"),
|
|
346
|
+
psd("adaptive"),
|
|
347
|
+
frames(file, dir, every, ffmpeg).then((shots) => readScreen(shots, opts.cohereKeys, call)),
|
|
348
|
+
opts.speech === false || !facts.audio
|
|
349
|
+
? Promise.resolve("")
|
|
350
|
+
: speech(file, dir, ffmpeg, opts.cohereKeys, { language: opts.language ?? "en", ...call }),
|
|
351
|
+
opts.geminiKeys?.length
|
|
352
|
+
? geminiScreen(file, dir, opts.geminiKeys, {
|
|
353
|
+
ffmpeg,
|
|
354
|
+
fetchFn,
|
|
355
|
+
info: {
|
|
356
|
+
duration: durationS,
|
|
357
|
+
...(facts.width ? { width: facts.width } : {}),
|
|
358
|
+
...(facts.height ? { height: facts.height } : {}),
|
|
359
|
+
},
|
|
360
|
+
}).catch(() => undefined)
|
|
361
|
+
: Promise.resolve(undefined),
|
|
362
|
+
]);
|
|
363
|
+
return {
|
|
364
|
+
durationS: Math.round(durationS * 100) / 100,
|
|
365
|
+
cuts: c,
|
|
366
|
+
...(opts.sceneDetect ? { cutsBy: { hash: h, adaptive: a } } : {}),
|
|
367
|
+
audio: facts.audio,
|
|
368
|
+
speech: s,
|
|
369
|
+
frames: f,
|
|
370
|
+
...(g ? { gemini: g } : {}),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
finally {
|
|
374
|
+
await rm(dir, { recursive: true, force: true });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// -- the page -----------------------------------------------------------------------------
|
|
378
|
+
/** The frames with something to say, each under its ffmpeg frame time; the unread ones say so. */
|
|
379
|
+
export function onScreenLines(w) {
|
|
380
|
+
return w.frames.flatMap((f) => f.text === null
|
|
381
|
+
? [`[${clock(f.at)}] (not read)`]
|
|
382
|
+
: f.text
|
|
383
|
+
? [`[${clock(f.at)}] ${f.text}`]
|
|
384
|
+
: []);
|
|
385
|
+
}
|
|
386
|
+
export const cutsLine = (w) => w.cuts.length ? w.cuts.map(stamp).join(", ") : "(none)";
|
|
387
|
+
/** `read`, `unread`: how many frames the model returned a line for. */
|
|
388
|
+
export function frameCounts(w) {
|
|
389
|
+
const unread = w.frames.filter((f) => f.text === null).length;
|
|
390
|
+
return { read: w.frames.length - unread, unread };
|
|
391
|
+
}
|
|
392
|
+
export const watchFacts = (w) => ({
|
|
393
|
+
duration_s: w.durationS,
|
|
394
|
+
audio: w.audio,
|
|
395
|
+
cuts_by: { ffmpeg: w.cuts, ...(w.cutsBy ?? {}) },
|
|
396
|
+
});
|
|
397
|
+
/** The facts fence of a rendered page, when it has one. */
|
|
398
|
+
export function readWatchFacts(md) {
|
|
399
|
+
const m = /## Facts\n\n```json\n([\s\S]*?)\n```/.exec(md);
|
|
400
|
+
if (!m)
|
|
401
|
+
return null;
|
|
402
|
+
try {
|
|
403
|
+
return JSON.parse(m[1]);
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
export function renderWatched(w) {
|
|
410
|
+
const screen = onScreenLines(w).join("\n") || "(no text on screen)";
|
|
411
|
+
return [
|
|
412
|
+
`## Speech\n\n${w.speech || "(no speech)"}`,
|
|
413
|
+
`## On screen\n\n${screen}`,
|
|
414
|
+
...(w.gemini ? [`## On screen (Gemini)\n\n${w.gemini}`] : []),
|
|
415
|
+
`## Cuts\n\n${cutsLine(w)}`,
|
|
416
|
+
// Only a film's page carries the fence: a reel's cuts are the line above.
|
|
417
|
+
...(w.cutsBy ? [`## Facts\n\n\`\`\`json\n${JSON.stringify(watchFacts(w))}\n\`\`\``] : []),
|
|
418
|
+
].join("\n\n");
|
|
419
|
+
}
|
|
420
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/video/watch.ts"],"names":[],"mappings":"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"}
|