@khorsheed/dsh-reader 0.3.0 → 0.3.2
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/CHANGELOG.md +29 -0
- package/README.en.md +26 -121
- package/README.i18n.yaml +3 -3
- package/README.md +26 -121
- package/cordis.patch.yml +7 -0
- package/lib/client.js +29105 -6692
- package/lib/index.js +3500 -321
- package/lib/typert.host.js +2145 -259
- package/lib/typert.remote-client.d.ts +97 -3
- package/lib/typert.remote-client.js +1590 -250
- package/lib/types/captions.d.ts +99 -0
- package/lib/types/captions.js +236 -0
- package/lib/types/client/MediaPlayer.d.ts +55 -0
- package/lib/types/client/MediaPlayer.js +106 -0
- package/lib/types/client/NotesView.d.ts +57 -0
- package/lib/types/client/NotesView.js +124 -0
- package/lib/types/client/ReaderPane.d.ts +20 -3
- package/lib/types/client/ReaderPane.js +860 -164
- package/lib/types/client/SpeakerLegend.d.ts +18 -0
- package/lib/types/client/SpeakerLegend.js +26 -0
- package/lib/types/client/canvas-sync.d.ts +84 -0
- package/lib/types/client/canvas-sync.js +59 -0
- package/lib/types/client/contract.d.ts +130 -3
- package/lib/types/client/extract-article.d.ts +38 -1
- package/lib/types/client/extract-article.js +561 -33
- package/lib/types/client/icons.d.ts +1 -1
- package/lib/types/client/icons.js +1 -1
- package/lib/types/client/index.js +81 -2
- package/lib/types/client/locales.d.ts +279 -11
- package/lib/types/client/locales.js +278 -10
- package/lib/types/client/notes.d.ts +142 -0
- package/lib/types/client/notes.js +334 -0
- package/lib/types/client/parse-rss.js +40 -0
- package/lib/types/client/preset-visibility.d.ts +93 -0
- package/lib/types/client/preset-visibility.js +115 -0
- package/lib/types/client/selectors.d.ts +5 -0
- package/lib/types/client/selectors.js +5 -0
- package/lib/types/client/session.d.ts +21 -1
- package/lib/types/client/session.js +12 -0
- package/lib/types/client/store.js +4 -1
- package/lib/types/client/translate.d.ts +26 -1
- package/lib/types/client/translate.js +29 -12
- package/lib/types/client/useLocalTranscript.d.ts +43 -0
- package/lib/types/client/useLocalTranscript.js +129 -0
- package/lib/types/client/useMedia.d.ts +68 -0
- package/lib/types/client/useMedia.js +299 -0
- package/lib/types/client/useMediaStates.d.ts +9 -0
- package/lib/types/client/useMediaStates.js +43 -0
- package/lib/types/client/useNotes.d.ts +110 -0
- package/lib/types/client/useNotes.js +423 -0
- package/lib/types/client/usePolish.d.ts +47 -0
- package/lib/types/client/usePolish.js +162 -0
- package/lib/types/document-fetch.d.ts +106 -0
- package/lib/types/document-fetch.js +100 -0
- package/lib/types/index.d.ts +15 -0
- package/lib/types/index.js +3 -0
- package/lib/types/local-transcribe.d.ts +171 -0
- package/lib/types/local-transcribe.js +473 -0
- package/lib/types/media-host.d.ts +91 -0
- package/lib/types/media-host.js +230 -0
- package/lib/types/media.d.ts +100 -0
- package/lib/types/media.js +207 -0
- package/lib/types/notes-types.d.ts +158 -0
- package/lib/types/notes-types.js +8 -0
- package/lib/types/notes.d.ts +213 -0
- package/lib/types/notes.js +718 -0
- package/lib/types/polish.d.ts +41 -0
- package/lib/types/polish.js +136 -0
- package/lib/types/remote.d.ts +118 -0
- package/lib/types/remote.js +151 -1
- package/lib/types/service.d.ts +81 -6
- package/lib/types/service.js +286 -65
- package/lib/types/skill.d.ts +20 -0
- package/lib/types/skill.js +78 -0
- package/lib/types/store.js +30 -8
- package/lib/types/tool.d.ts +23 -0
- package/lib/types/tool.js +40 -0
- package/lib/types/tools.d.ts +69 -0
- package/lib/types/tools.js +400 -0
- package/lib/types/types.d.ts +90 -2
- package/lib/types/types.js +66 -0
- package/lib/types/xiaoyuzhou.d.ts +43 -0
- package/lib/types/xiaoyuzhou.js +134 -0
- package/lib/types/ytdlp.d.ts +111 -0
- package/lib/types/ytdlp.js +269 -0
- package/package.json +33 -20
- package/lib/invariant.js +0 -38
- package/lib/types/invariant.d.ts +0 -29
- package/lib/types/invariant.js +0 -38
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document fetcher: the reader's own instance of the official HTTP fetch
|
|
3
|
+
* provider, so feeds and article pages arrive as the origin served them.
|
|
4
|
+
*
|
|
5
|
+
* Why not `ctx.web.fetch` alone: the seam runs whichever provider the host
|
|
6
|
+
* selects, and from 0.2.1-rc.2 the web-search settings switch for the DeepSeek
|
|
7
|
+
* Search/Fetch API moves `web.fetchProvider` too. That provider answers
|
|
8
|
+
* Markdown (`body.kind: 'text'`), a constant 200, and the request URL as the
|
|
9
|
+
* final URL — so `classifyPayload` reads every feed as a page, the extractor
|
|
10
|
+
* gets no HTML, and the cross-origin redirect handling never fires. The
|
|
11
|
+
* request carries only a URL; no caller can ask for the HTTP provider (seam
|
|
12
|
+
* registry S22).
|
|
13
|
+
*
|
|
14
|
+
* So when the mounted `web` is the official service (it carries
|
|
15
|
+
* `registerFetchProvider`), the reader fetches through its own
|
|
16
|
+
* `HttpFetchProvider` — the same class the default `http` row registers, with
|
|
17
|
+
* that row's default limits, so the policy (public addresses only, connection
|
|
18
|
+
* pinned, same-origin redirects, charset decoding) and the errors
|
|
19
|
+
* (`WEB_REDIRECT_BLOCKED` naming the target origin) are exactly today's.
|
|
20
|
+
* `ctx.web` stays the permission: without it nothing is fetched. A host
|
|
21
|
+
* without the provider package (or any other `web` shape, such as a test's
|
|
22
|
+
* plain `{ fetch }`) is fetched through as before.
|
|
23
|
+
*
|
|
24
|
+
* Retire when the seam lets one request name its provider (S22).
|
|
25
|
+
*
|
|
26
|
+
* @module @khorsheed/dsh-reader/document-fetch
|
|
27
|
+
*/
|
|
28
|
+
/** The shape of one fetch result, declared structurally (no host import). */
|
|
29
|
+
export interface DocumentFetchResult {
|
|
30
|
+
readonly url: string;
|
|
31
|
+
readonly statusCode: number;
|
|
32
|
+
readonly body: {
|
|
33
|
+
readonly kind: 'html' | 'text';
|
|
34
|
+
readonly content: string;
|
|
35
|
+
};
|
|
36
|
+
readonly truncated: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Anything that fetches one URL: the web seam or a provider. */
|
|
39
|
+
export interface DocumentFetcher {
|
|
40
|
+
fetch(request: {
|
|
41
|
+
readonly url: string;
|
|
42
|
+
}, signal?: AbortSignal): Promise<DocumentFetchResult>;
|
|
43
|
+
}
|
|
44
|
+
/** The limits the official provider takes (the `http` row's resolved config). */
|
|
45
|
+
interface HttpFetchLimits {
|
|
46
|
+
readonly maxResponseBytes: number;
|
|
47
|
+
readonly maxBodyChars: number;
|
|
48
|
+
readonly timeoutMs: number;
|
|
49
|
+
readonly maxRedirects: number;
|
|
50
|
+
readonly userAgent: string;
|
|
51
|
+
}
|
|
52
|
+
/** The provider package's runtime face, structurally. */
|
|
53
|
+
interface HttpProviderModule {
|
|
54
|
+
readonly HttpFetchProvider: new (limits: HttpFetchLimits) => DocumentFetcher;
|
|
55
|
+
readonly DEFAULT_USER_AGENT?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The reader's own fetch limits: the `http` row's defaults
|
|
59
|
+
* (`@deepseek-ai/dsh-web-fetch-http` Config, 0.1.5 through 0.2.1-rc.3) except
|
|
60
|
+
* `maxBodyChars`. The row's 100 000 is sized for a page handed to a model; the
|
|
61
|
+
* reader extracts the article itself from the raw HTML, and a modern page
|
|
62
|
+
* carries several hundred KB of inline script before its last paragraph
|
|
63
|
+
* (measured: claude.com's articles, 620 KB, cut mid-sentence at 100 000). 2 000 000
|
|
64
|
+
* is what deployments ran the row at while the reader still fetched through
|
|
65
|
+
* it, and the per-source storage budget (`MAX_BODY_CHARS_PER_SOURCE`) is
|
|
66
|
+
* sized to match. A deployment changes these with the reader's own
|
|
67
|
+
* `fetchLimits`: the row's config does not reach this instance.
|
|
68
|
+
*/
|
|
69
|
+
export declare const DOCUMENT_FETCH_DEFAULTS: {
|
|
70
|
+
readonly maxResponseBytes: 5000000;
|
|
71
|
+
readonly maxBodyChars: 2000000;
|
|
72
|
+
readonly timeoutMs: 30000;
|
|
73
|
+
readonly maxRedirects: 5;
|
|
74
|
+
};
|
|
75
|
+
/** The limits a deployment may override (the user agent stays the provider's). */
|
|
76
|
+
export type DocumentFetchLimits = Partial<Pick<HttpFetchLimits, 'maxResponseBytes' | 'maxBodyChars' | 'timeoutMs' | 'maxRedirects'>>;
|
|
77
|
+
/** Whether a mounted `web` is the official service rather than some other shape. */
|
|
78
|
+
export declare function isOfficialWebService(web: unknown): boolean;
|
|
79
|
+
/** Loads the provider package; injectable so tests never need the real one. */
|
|
80
|
+
export type HttpProviderLoader = () => Promise<HttpProviderModule | undefined>;
|
|
81
|
+
/**
|
|
82
|
+
* Pick the fetcher for raw documents.
|
|
83
|
+
*
|
|
84
|
+
* Built once per service: the first fetch on an official web service loads
|
|
85
|
+
* the provider package and keeps the instance; a failed load is remembered
|
|
86
|
+
* too, and every later fetch goes through the seam.
|
|
87
|
+
*/
|
|
88
|
+
export declare class DocumentFetch {
|
|
89
|
+
private readonly web;
|
|
90
|
+
private readonly limits;
|
|
91
|
+
private readonly load;
|
|
92
|
+
private provider;
|
|
93
|
+
/**
|
|
94
|
+
* @param web - the probed web seam, read on every call (it may come and go).
|
|
95
|
+
* @param limits - the reader's configured fetch limits, over the defaults.
|
|
96
|
+
* @param load - the provider package loader (tests inject one).
|
|
97
|
+
*/
|
|
98
|
+
constructor(web: () => unknown, limits?: DocumentFetchLimits, load?: HttpProviderLoader);
|
|
99
|
+
/**
|
|
100
|
+
* The fetcher for this call, or undefined when no web capability is mounted.
|
|
101
|
+
* @returns the reader's own provider on an official web service, else the seam itself.
|
|
102
|
+
*/
|
|
103
|
+
current(): Promise<DocumentFetcher | undefined>;
|
|
104
|
+
}
|
|
105
|
+
export {};
|
|
106
|
+
//# sourceMappingURL=document-fetch.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document fetcher: the reader's own instance of the official HTTP fetch
|
|
3
|
+
* provider, so feeds and article pages arrive as the origin served them.
|
|
4
|
+
*
|
|
5
|
+
* Why not `ctx.web.fetch` alone: the seam runs whichever provider the host
|
|
6
|
+
* selects, and from 0.2.1-rc.2 the web-search settings switch for the DeepSeek
|
|
7
|
+
* Search/Fetch API moves `web.fetchProvider` too. That provider answers
|
|
8
|
+
* Markdown (`body.kind: 'text'`), a constant 200, and the request URL as the
|
|
9
|
+
* final URL — so `classifyPayload` reads every feed as a page, the extractor
|
|
10
|
+
* gets no HTML, and the cross-origin redirect handling never fires. The
|
|
11
|
+
* request carries only a URL; no caller can ask for the HTTP provider (seam
|
|
12
|
+
* registry S22).
|
|
13
|
+
*
|
|
14
|
+
* So when the mounted `web` is the official service (it carries
|
|
15
|
+
* `registerFetchProvider`), the reader fetches through its own
|
|
16
|
+
* `HttpFetchProvider` — the same class the default `http` row registers, with
|
|
17
|
+
* that row's default limits, so the policy (public addresses only, connection
|
|
18
|
+
* pinned, same-origin redirects, charset decoding) and the errors
|
|
19
|
+
* (`WEB_REDIRECT_BLOCKED` naming the target origin) are exactly today's.
|
|
20
|
+
* `ctx.web` stays the permission: without it nothing is fetched. A host
|
|
21
|
+
* without the provider package (or any other `web` shape, such as a test's
|
|
22
|
+
* plain `{ fetch }`) is fetched through as before.
|
|
23
|
+
*
|
|
24
|
+
* Retire when the seam lets one request name its provider (S22).
|
|
25
|
+
*
|
|
26
|
+
* @module @khorsheed/dsh-reader/document-fetch
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* The reader's own fetch limits: the `http` row's defaults
|
|
30
|
+
* (`@deepseek-ai/dsh-web-fetch-http` Config, 0.1.5 through 0.2.1-rc.3) except
|
|
31
|
+
* `maxBodyChars`. The row's 100 000 is sized for a page handed to a model; the
|
|
32
|
+
* reader extracts the article itself from the raw HTML, and a modern page
|
|
33
|
+
* carries several hundred KB of inline script before its last paragraph
|
|
34
|
+
* (measured: claude.com's articles, 620 KB, cut mid-sentence at 100 000). 2 000 000
|
|
35
|
+
* is what deployments ran the row at while the reader still fetched through
|
|
36
|
+
* it, and the per-source storage budget (`MAX_BODY_CHARS_PER_SOURCE`) is
|
|
37
|
+
* sized to match. A deployment changes these with the reader's own
|
|
38
|
+
* `fetchLimits`: the row's config does not reach this instance.
|
|
39
|
+
*/
|
|
40
|
+
export const DOCUMENT_FETCH_DEFAULTS = {
|
|
41
|
+
maxResponseBytes: 5_000_000,
|
|
42
|
+
maxBodyChars: 2_000_000,
|
|
43
|
+
timeoutMs: 30_000,
|
|
44
|
+
maxRedirects: 5,
|
|
45
|
+
};
|
|
46
|
+
/** Whether a mounted `web` is the official service rather than some other shape. */
|
|
47
|
+
export function isOfficialWebService(web) {
|
|
48
|
+
return typeof web?.registerFetchProvider === 'function';
|
|
49
|
+
}
|
|
50
|
+
const loadOfficialProvider = () => import('@deepseek-ai/dsh-web-fetch-http').then(module => module, () => undefined);
|
|
51
|
+
/**
|
|
52
|
+
* Pick the fetcher for raw documents.
|
|
53
|
+
*
|
|
54
|
+
* Built once per service: the first fetch on an official web service loads
|
|
55
|
+
* the provider package and keeps the instance; a failed load is remembered
|
|
56
|
+
* too, and every later fetch goes through the seam.
|
|
57
|
+
*/
|
|
58
|
+
export class DocumentFetch {
|
|
59
|
+
web;
|
|
60
|
+
limits;
|
|
61
|
+
load;
|
|
62
|
+
provider;
|
|
63
|
+
/**
|
|
64
|
+
* @param web - the probed web seam, read on every call (it may come and go).
|
|
65
|
+
* @param limits - the reader's configured fetch limits, over the defaults.
|
|
66
|
+
* @param load - the provider package loader (tests inject one).
|
|
67
|
+
*/
|
|
68
|
+
constructor(web, limits = {}, load = loadOfficialProvider) {
|
|
69
|
+
this.web = web;
|
|
70
|
+
this.limits = limits;
|
|
71
|
+
this.load = load;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The fetcher for this call, or undefined when no web capability is mounted.
|
|
75
|
+
* @returns the reader's own provider on an official web service, else the seam itself.
|
|
76
|
+
*/
|
|
77
|
+
async current() {
|
|
78
|
+
const web = this.web();
|
|
79
|
+
if (web === undefined || web === null)
|
|
80
|
+
return undefined;
|
|
81
|
+
const seam = web;
|
|
82
|
+
if (!isOfficialWebService(web))
|
|
83
|
+
return seam;
|
|
84
|
+
this.provider ??= this.load().then(module => {
|
|
85
|
+
if (module === undefined || typeof module.HttpFetchProvider !== 'function')
|
|
86
|
+
return undefined;
|
|
87
|
+
try {
|
|
88
|
+
return new module.HttpFetchProvider({
|
|
89
|
+
...DOCUMENT_FETCH_DEFAULTS,
|
|
90
|
+
...this.limits,
|
|
91
|
+
userAgent: module.DEFAULT_USER_AGENT ?? 'deepseek-harness/0.0.1 (+https://github.com/deepseek-ai)',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return (await this.provider) ?? seam;
|
|
99
|
+
}
|
|
100
|
+
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -12,18 +12,23 @@
|
|
|
12
12
|
* @module @khorsheed/dsh-reader
|
|
13
13
|
*/
|
|
14
14
|
import type { Context } from '@deepseek-ai/cordis';
|
|
15
|
+
import type { DocumentFetchLimits } from './document-fetch.ts';
|
|
15
16
|
import { ReaderService } from './service.ts';
|
|
17
|
+
import { ReaderNotesStore } from './notes.ts';
|
|
16
18
|
export { ReaderService, classifyPayload, normalizeUrl } from './service.ts';
|
|
17
19
|
export { ReaderRemoteService } from './remote.ts';
|
|
18
20
|
export type { ReaderRemoteConfig } from './remote.ts';
|
|
19
21
|
export { MAX_CACHED_BODIES, MAX_TAGS, ReaderStore, ReaderStoreError, boundAnnotations, boundPayloads, emptyStateDoc, normalizeStateDoc, pruneOrphanTags, resolveReaderStateRoot, serializeStateDoc, } from './store.ts';
|
|
20
22
|
export type { ReaderStoreRead } from './store.ts';
|
|
23
|
+
export * from './notes.ts';
|
|
21
24
|
export * from './schedule.ts';
|
|
22
25
|
export * from './types.ts';
|
|
23
26
|
declare module '@deepseek-ai/cordis' {
|
|
24
27
|
interface Context {
|
|
25
28
|
/** The reader plugin's service core. */
|
|
26
29
|
reader: ReaderService;
|
|
30
|
+
/** The reader's notes, discussions and article snapshots. */
|
|
31
|
+
readerNotes: ReaderNotesStore;
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
/** Cordis plugin name used by loader diagnostics. */
|
|
@@ -32,6 +37,16 @@ export declare const name = "reader";
|
|
|
32
37
|
export interface ReaderConfig {
|
|
33
38
|
/** Directory holding `state.json`; defaults to `$DSH_HOME/state/dsh-reader`. */
|
|
34
39
|
readonly stateRoot?: string;
|
|
40
|
+
/** A yt-dlp binary to use instead of the reader's managed copy (video metadata and captions). */
|
|
41
|
+
readonly ytdlpPath?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Fetch limits for feeds and pages: `maxResponseBytes` (default 5 000 000),
|
|
44
|
+
* `maxBodyChars` (2 000 000 — whole pages, not the row's model-sized 100 000),
|
|
45
|
+
* `timeoutMs` (30 000), `maxRedirects` (5). The reader fetches through its own
|
|
46
|
+
* instance of the official `http` provider, so limits raised on that row do
|
|
47
|
+
* not reach it; set them here.
|
|
48
|
+
*/
|
|
49
|
+
readonly fetchLimits?: DocumentFetchLimits;
|
|
35
50
|
}
|
|
36
51
|
/**
|
|
37
52
|
* Plugin body: provide the service core, then mount the Remote data face.
|
package/lib/types/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ReaderService } from "./service.js";
|
|
2
|
+
import { ReaderNotesStore } from "./notes.js";
|
|
2
3
|
import { ReaderRemoteService } from "./remote.js";
|
|
3
4
|
export { ReaderService, classifyPayload, normalizeUrl } from "./service.js";
|
|
4
5
|
export { ReaderRemoteService } from "./remote.js";
|
|
5
6
|
export { MAX_CACHED_BODIES, MAX_TAGS, ReaderStore, ReaderStoreError, boundAnnotations, boundPayloads, emptyStateDoc, normalizeStateDoc, pruneOrphanTags, resolveReaderStateRoot, serializeStateDoc, } from "./store.js";
|
|
7
|
+
export * from "./notes.js";
|
|
6
8
|
export * from "./schedule.js";
|
|
7
9
|
export * from "./types.js";
|
|
8
10
|
/** Cordis plugin name used by loader diagnostics. */
|
|
@@ -21,5 +23,6 @@ export const name = 'reader';
|
|
|
21
23
|
export function apply(ctx, config = {}) {
|
|
22
24
|
const service = new ReaderService(ctx, config);
|
|
23
25
|
ctx.provide('reader', service);
|
|
26
|
+
ctx.provide('readerNotes', new ReaderNotesStore(config));
|
|
24
27
|
ctx.plugin(ReaderRemoteService, {});
|
|
25
28
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { type Cue } from './captions.ts';
|
|
2
|
+
import type { ReaderMedia } from './media.ts';
|
|
3
|
+
import type { LocalTranscriptStatus } from './types.ts';
|
|
4
|
+
/** The part of the `transcribe` service the reader calls. */
|
|
5
|
+
export interface TranscribeEngine {
|
|
6
|
+
modelsFor(request: {
|
|
7
|
+
language?: 'zh' | 'en' | 'auto';
|
|
8
|
+
diarize?: false;
|
|
9
|
+
}): string[];
|
|
10
|
+
missingBytes(ids: readonly string[]): Promise<number>;
|
|
11
|
+
run(request: {
|
|
12
|
+
input: {
|
|
13
|
+
files: string[];
|
|
14
|
+
};
|
|
15
|
+
fromSec?: number;
|
|
16
|
+
language: 'zh' | 'en' | 'auto';
|
|
17
|
+
diarize: false;
|
|
18
|
+
owner: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
}, options: {
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
onProgress?: (progress: {
|
|
23
|
+
stage: string;
|
|
24
|
+
progress: number;
|
|
25
|
+
ahead?: number;
|
|
26
|
+
}) => void;
|
|
27
|
+
onSegments?: (segments: readonly EngineSegment[]) => void;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
segments: EngineSegment[];
|
|
30
|
+
language?: string;
|
|
31
|
+
}>;
|
|
32
|
+
/** Who spoke when (an engine older than this has none: transcripts stay one voice). */
|
|
33
|
+
speakers?(request: {
|
|
34
|
+
input: {
|
|
35
|
+
files: string[];
|
|
36
|
+
};
|
|
37
|
+
speech?: {
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
}[];
|
|
41
|
+
owner: string;
|
|
42
|
+
label?: string;
|
|
43
|
+
}, options: {
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
onProgress?: (progress: {
|
|
46
|
+
stage: string;
|
|
47
|
+
progress: number;
|
|
48
|
+
ahead?: number;
|
|
49
|
+
}) => void;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
single: boolean;
|
|
52
|
+
turns: {
|
|
53
|
+
cluster: number;
|
|
54
|
+
start: number;
|
|
55
|
+
end: number;
|
|
56
|
+
}[];
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
/** A speaker turn as the engine reports it. */
|
|
60
|
+
export interface EngineTurn {
|
|
61
|
+
readonly cluster: number;
|
|
62
|
+
readonly start: number;
|
|
63
|
+
readonly end: number;
|
|
64
|
+
}
|
|
65
|
+
/** One finished stretch as the engine reports it. */
|
|
66
|
+
export interface EngineSegment {
|
|
67
|
+
readonly start: number;
|
|
68
|
+
readonly end: number;
|
|
69
|
+
readonly tokens: readonly {
|
|
70
|
+
readonly text: string;
|
|
71
|
+
readonly start: number;
|
|
72
|
+
readonly end: number;
|
|
73
|
+
}[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Engine stretches as caption-like cues: one per sentence (the engine's
|
|
77
|
+
* stretches are cut at pauses, not sentence ends), so the transcript merges
|
|
78
|
+
* into the same paragraphs platform captions do. A sentence that runs on
|
|
79
|
+
* without a period is closed at a comma or a pause once it is long, or a
|
|
80
|
+
* single cue would make a minute-and-a-half paragraph (measured 2026-10-20).
|
|
81
|
+
*
|
|
82
|
+
* @param segments - the engine's segments, in order.
|
|
83
|
+
*/
|
|
84
|
+
export declare function cuesFromSegments(segments: readonly EngineSegment[], speakers?: readonly (number | undefined)[]): (Cue & {
|
|
85
|
+
speaker?: number;
|
|
86
|
+
})[];
|
|
87
|
+
/**
|
|
88
|
+
* Each token's speaker, as an index in order of first appearance (A, B, …):
|
|
89
|
+
* the turn covering the token's middle, else the nearest one; then runs of a
|
|
90
|
+
* voice shorter than {@link MIN_TURN_SEC} are folded into the voice before
|
|
91
|
+
* them — a diarizer's boundary wobble would otherwise split sentences.
|
|
92
|
+
*
|
|
93
|
+
* @param segments - the transcript's segments.
|
|
94
|
+
* @param turns - the engine's turns.
|
|
95
|
+
*/
|
|
96
|
+
export declare function speakerPerToken(segments: readonly EngineSegment[], turns: readonly EngineTurn[]): number[];
|
|
97
|
+
/**
|
|
98
|
+
* The transcript with its speakers: paragraphs never cross a change of voice,
|
|
99
|
+
* and each carries `data-spk` (the speaker's index) beside its `data-t`.
|
|
100
|
+
*/
|
|
101
|
+
export declare function renderSpeakerTranscript(segments: readonly EngineSegment[], turns: readonly EngineTurn[]): string;
|
|
102
|
+
/** The marker a locally transcribed paragraph carries (the 来源 line reads it). */
|
|
103
|
+
export declare const LOCAL_MARK = "data-src=\"local\"";
|
|
104
|
+
/** The engine's segments as transcript markup, each paragraph marked local. */
|
|
105
|
+
export declare function renderLocalTranscript(segments: readonly EngineSegment[]): string;
|
|
106
|
+
/**
|
|
107
|
+
* The language to ask for: always detection (SenseVoice). Measured
|
|
108
|
+
* 2026-10-20: a platform says nothing reliable about the spoken language — a
|
|
109
|
+
* Bilibili upload of an English interview came out of the Chinese model as
|
|
110
|
+
* lower-case English with Chinese punctuation — and on Chinese speech
|
|
111
|
+
* SenseVoice reads about as well as Paraformer (a 90 s sample: each missed
|
|
112
|
+
* two or three characters the other got right).
|
|
113
|
+
*/
|
|
114
|
+
export declare function languageFor(_media: ReaderMedia): 'auto';
|
|
115
|
+
/** What the transcriber needs from the reader. */
|
|
116
|
+
export interface LocalTranscriberDeps {
|
|
117
|
+
/** The engine, probed per start. */
|
|
118
|
+
readonly engine: () => TranscribeEngine | undefined;
|
|
119
|
+
/** Where temporary audio goes. */
|
|
120
|
+
readonly tmpRoot: string;
|
|
121
|
+
/** Fetch a video's audio track into `dir`. */
|
|
122
|
+
readonly videoAudio: (url: string, dir: string, options: {
|
|
123
|
+
signal: AbortSignal;
|
|
124
|
+
onProgress: (fraction: number) => void;
|
|
125
|
+
}) => Promise<string>;
|
|
126
|
+
/** How often a restart checks for the engine before resuming jobs (ms; default 2 s). */
|
|
127
|
+
readonly resumePollMs?: number;
|
|
128
|
+
/** Keep the finished transcript as the entry's body (`speakers`: how many voices, once known). */
|
|
129
|
+
readonly store: (entryId: string, url: string, html: string, language: string | undefined, speakers?: number) => Promise<void>;
|
|
130
|
+
}
|
|
131
|
+
/** The reader's local transcription jobs, by entry. */
|
|
132
|
+
export declare class LocalTranscriber {
|
|
133
|
+
private readonly deps;
|
|
134
|
+
private readonly jobs;
|
|
135
|
+
/** Jobs a previous process left mid-way, waiting for the engine. */
|
|
136
|
+
private readonly resumable;
|
|
137
|
+
private resumeTimer;
|
|
138
|
+
private disposing;
|
|
139
|
+
constructor(deps: LocalTranscriberDeps);
|
|
140
|
+
/** An entry's job as the browser sees it. */
|
|
141
|
+
status(entryId: string): LocalTranscriptStatus;
|
|
142
|
+
/**
|
|
143
|
+
* Start (or rejoin) an entry's transcription.
|
|
144
|
+
*
|
|
145
|
+
* @param request - the entry, its media, and whether the model download was confirmed.
|
|
146
|
+
*/
|
|
147
|
+
start(request: {
|
|
148
|
+
entryId: string;
|
|
149
|
+
url: string;
|
|
150
|
+
media: ReaderMedia;
|
|
151
|
+
title?: string;
|
|
152
|
+
confirmModels?: boolean;
|
|
153
|
+
}): Promise<LocalTranscriptStatus>;
|
|
154
|
+
/**
|
|
155
|
+
* Leave or stop an entry's job: a queued (or still fetching) job is
|
|
156
|
+
* withdrawn either way; a running one only with `force`.
|
|
157
|
+
*/
|
|
158
|
+
cancel(entryId: string, force: boolean): LocalTranscriptStatus;
|
|
159
|
+
/** Whether the engine is installed right now. */
|
|
160
|
+
engineAvailable(): boolean;
|
|
161
|
+
/** Stop everything (plugin disposal) — keeping each job's record, so the next process resumes it. */
|
|
162
|
+
dispose(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Run (or resume) one job: fetch the audio unless the record has it,
|
|
165
|
+
* transcribe from where the saved segments end, store, then the speakers.
|
|
166
|
+
*
|
|
167
|
+
* @param resumeDir - a previous process's directory for this job.
|
|
168
|
+
*/
|
|
169
|
+
private execute;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=local-transcribe.d.ts.map
|