@urun-sh/sense 0.0.0-stage → 0.1.1
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 +201 -0
- package/README.md +38 -2
- package/dist/context.d.ts +44 -0
- package/dist/context.js +110 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +9 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +9 -0
- package/dist/predicate.d.ts +81 -0
- package/dist/predicate.js +132 -0
- package/dist/question.d.ts +43 -0
- package/dist/question.js +75 -0
- package/dist/sense.d.ts +54 -0
- package/dist/sense.js +109 -0
- package/dist/session.d.ts +151 -0
- package/dist/session.js +472 -0
- package/dist/transport.d.ts +106 -0
- package/dist/transport.js +467 -0
- package/dist/wave.d.ts +58 -0
- package/dist/wave.js +209 -0
- package/examples/assets/mic-question-48k-mono.wav +0 -0
- package/examples/cheese_demo.html +290 -0
- package/examples/cheese_demo.test.ts +191 -0
- package/examples/cheese_demo.ts +250 -0
- package/examples/voice_agent.ts +166 -0
- package/package.json +55 -4
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Predicate } from "./predicate.js";
|
|
2
|
+
export type QuestionKind = "noul" | "choice" | "score";
|
|
3
|
+
export interface QuestionInit {
|
|
4
|
+
id: string;
|
|
5
|
+
kind: QuestionKind;
|
|
6
|
+
prompt?: string;
|
|
7
|
+
/** choice option names (noul: server defaults to true/false). */
|
|
8
|
+
options?: string[];
|
|
9
|
+
/** score level names, ordinal order. */
|
|
10
|
+
levels?: string[];
|
|
11
|
+
}
|
|
12
|
+
/** One registered question. */
|
|
13
|
+
export declare class Question {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly kind: QuestionKind;
|
|
16
|
+
readonly prompt?: string;
|
|
17
|
+
readonly options?: string[];
|
|
18
|
+
readonly levels?: string[];
|
|
19
|
+
constructor(init: QuestionInit);
|
|
20
|
+
/** argmax accessor: `actions.top.eq("respond")`. */
|
|
21
|
+
get top(): import("./predicate.js").Ops & ((option?: string) => import("./predicate.js").Ops);
|
|
22
|
+
/** score expected-ordinal accessor. */
|
|
23
|
+
get value(): import("./predicate.js").Ops & ((option?: string) => import("./predicate.js").Ops);
|
|
24
|
+
/** noul P(true) accessor; choice: `intent.p("support").gte(0.7)`. */
|
|
25
|
+
get p(): import("./predicate.js").Ops & ((option?: string) => import("./predicate.js").Ops);
|
|
26
|
+
/** score level-threshold accessor. */
|
|
27
|
+
pAtLeast(level: string): import("./predicate.js").Ops & ((option?: string) => import("./predicate.js").Ops);
|
|
28
|
+
private argmax;
|
|
29
|
+
eq(value: string | number | boolean): Predicate;
|
|
30
|
+
ne(value: string | number | boolean): Predicate;
|
|
31
|
+
gt(value: number): Predicate;
|
|
32
|
+
gte(value: number): Predicate;
|
|
33
|
+
lt(value: number): Predicate;
|
|
34
|
+
lte(value: number): Predicate;
|
|
35
|
+
and(...others: Predicate[]): Predicate;
|
|
36
|
+
or(...others: Predicate[]): Predicate;
|
|
37
|
+
not(): Predicate;
|
|
38
|
+
}
|
|
39
|
+
/** The §2 instructions envelope body (values, not the JSON string). */
|
|
40
|
+
export declare function instructionsEnvelope(questions: readonly Question[], hz: number): {
|
|
41
|
+
questions: Record<string, Record<string, unknown>>;
|
|
42
|
+
hz: number;
|
|
43
|
+
};
|
package/dist/question.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Questions and the instructions envelope (protocol §2). */
|
|
2
|
+
import { opsFor } from "./predicate.js";
|
|
3
|
+
/** One registered question. */
|
|
4
|
+
export class Question {
|
|
5
|
+
id;
|
|
6
|
+
kind;
|
|
7
|
+
prompt;
|
|
8
|
+
options;
|
|
9
|
+
levels;
|
|
10
|
+
constructor(init) {
|
|
11
|
+
this.id = init.id;
|
|
12
|
+
this.kind = init.kind;
|
|
13
|
+
this.prompt = init.prompt;
|
|
14
|
+
this.options = init.options;
|
|
15
|
+
this.levels = init.levels;
|
|
16
|
+
if (init.kind === "score" && (init.levels?.length ?? 0) < 2) {
|
|
17
|
+
throw new RangeError(`score question "${init.id}" needs 2..10 levels`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** argmax accessor: `actions.top.eq("respond")`. */
|
|
21
|
+
get top() {
|
|
22
|
+
return opsFor({ type: "top", question: this.id });
|
|
23
|
+
}
|
|
24
|
+
/** score expected-ordinal accessor. */
|
|
25
|
+
get value() {
|
|
26
|
+
return opsFor({ type: "value", question: this.id });
|
|
27
|
+
}
|
|
28
|
+
/** noul P(true) accessor; choice: `intent.p("support").gte(0.7)`. */
|
|
29
|
+
get p() {
|
|
30
|
+
return opsFor({ type: "p", question: this.id });
|
|
31
|
+
}
|
|
32
|
+
/** score level-threshold accessor. */
|
|
33
|
+
pAtLeast(level) {
|
|
34
|
+
return opsFor({ type: "p_at_least", question: this.id, level });
|
|
35
|
+
}
|
|
36
|
+
// Argmax sugar on the question itself: `intent.eq("support")` == the top
|
|
37
|
+
// option equals "support"; `finished.eq(true)` / `finished.and(...)` /
|
|
38
|
+
// `finished.not()` for noul. Same trees the accessors build.
|
|
39
|
+
argmax() {
|
|
40
|
+
return opsFor({ type: "question", id: this.id });
|
|
41
|
+
}
|
|
42
|
+
eq(value) { return this.argmax().eq(value); }
|
|
43
|
+
ne(value) { return this.argmax().ne(value); }
|
|
44
|
+
gt(value) { return this.argmax().gt(value); }
|
|
45
|
+
gte(value) { return this.argmax().gte(value); }
|
|
46
|
+
lt(value) { return this.argmax().lt(value); }
|
|
47
|
+
lte(value) { return this.argmax().lte(value); }
|
|
48
|
+
and(...others) { return this.argmax().truthy().and(...others); }
|
|
49
|
+
or(...others) { return this.argmax().truthy().or(...others); }
|
|
50
|
+
not() { return this.argmax().truthy().not(); }
|
|
51
|
+
}
|
|
52
|
+
/** The §2 instructions envelope body (values, not the JSON string). */
|
|
53
|
+
export function instructionsEnvelope(questions, hz) {
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const q of questions) {
|
|
56
|
+
if (q.kind === "score") {
|
|
57
|
+
// The server's _score_levels wants an ORDERED ARRAY of level
|
|
58
|
+
// descriptions (a string parses as free text and the model then
|
|
59
|
+
// free-scores into ~10 unnamed buckets — live-verified).
|
|
60
|
+
out[q.id] = {
|
|
61
|
+
kind: q.kind,
|
|
62
|
+
prompt: q.prompt ?? "",
|
|
63
|
+
criteria: q.levels ?? [],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
out[q.id] = {
|
|
68
|
+
kind: q.kind,
|
|
69
|
+
prompt: q.prompt ?? "",
|
|
70
|
+
...(q.options ? { options: q.options } : {}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { questions: out, hz };
|
|
75
|
+
}
|
package/dist/sense.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Sense: the app facade — register questions, compose predicates, open sessions. */
|
|
2
|
+
import { Question } from "./question.js";
|
|
3
|
+
import type { QuestionKind } from "./question.js";
|
|
4
|
+
import type { Predicate } from "./predicate.js";
|
|
5
|
+
import type { WaveHandler } from "./context.js";
|
|
6
|
+
import { Session, type SessionOptions } from "./session.js";
|
|
7
|
+
import type { Transport } from "./transport.js";
|
|
8
|
+
export interface SenseOptions extends SessionOptions {
|
|
9
|
+
}
|
|
10
|
+
export declare class Sense {
|
|
11
|
+
readonly apiKey?: string;
|
|
12
|
+
readonly baseUrl?: string;
|
|
13
|
+
readonly model: string;
|
|
14
|
+
readonly hz: number;
|
|
15
|
+
readonly transport: Transport;
|
|
16
|
+
private questions;
|
|
17
|
+
private whens;
|
|
18
|
+
private waveHandlers;
|
|
19
|
+
constructor(opts?: SenseOptions);
|
|
20
|
+
/** Register a binary question. TEXT-FIRST like the python facade: the
|
|
21
|
+
* natural-language question is the first argument; the id is optional and
|
|
22
|
+
* auto-slugged from the question text (options optional; the server
|
|
23
|
+
* defaults to true/false). */
|
|
24
|
+
noul(question: string, opts?: {
|
|
25
|
+
id?: string;
|
|
26
|
+
options?: string[];
|
|
27
|
+
}): Question;
|
|
28
|
+
/** Register an n-way choice question (text-first; id auto-slugs). */
|
|
29
|
+
choice(question: string, options: string[], opts?: {
|
|
30
|
+
id?: string;
|
|
31
|
+
}): Question;
|
|
32
|
+
/** Register an ordinal score question, 2..10 levels (text-first; id auto-slugs). */
|
|
33
|
+
score(question: string, levels: string[], opts?: {
|
|
34
|
+
id?: string;
|
|
35
|
+
}): Question;
|
|
36
|
+
/** Mirror of python `_qid`: the question text is required and non-empty;
|
|
37
|
+
* the id is auto-slugged from it when omitted and must be non-empty when
|
|
38
|
+
* given explicitly. */
|
|
39
|
+
private qid;
|
|
40
|
+
private register;
|
|
41
|
+
when(pred: Predicate, handler: WaveHandler): {
|
|
42
|
+
cancel(): void;
|
|
43
|
+
};
|
|
44
|
+
/** Observe waves on every session opened from here; `coalesce` skips
|
|
45
|
+
* consecutive same-argmax waves (latest wins). */
|
|
46
|
+
onWave(handler: WaveHandler, opts?: {
|
|
47
|
+
coalesce?: boolean;
|
|
48
|
+
}): {
|
|
49
|
+
cancel(): void;
|
|
50
|
+
};
|
|
51
|
+
/** Open a session carrying the questions and handlers registered here. */
|
|
52
|
+
session(): Session;
|
|
53
|
+
}
|
|
54
|
+
export type { QuestionKind };
|
package/dist/sense.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/** Sense: the app facade — register questions, compose predicates, open sessions. */
|
|
2
|
+
import { Question } from "./question.js";
|
|
3
|
+
import { Session } from "./session.js";
|
|
4
|
+
/** Mirror of python `_slug`: lowercase, each non-alphanumeric char becomes
|
|
5
|
+
* `_`, leading/trailing `_` trimmed, never empty, unique within the app. */
|
|
6
|
+
function slug(text, taken) {
|
|
7
|
+
let base = "";
|
|
8
|
+
for (const c of text.trim().toLowerCase())
|
|
9
|
+
base += /\p{L}|\p{N}/u.test(c) ? c : "_";
|
|
10
|
+
base = base.replace(/^_+/, "").replace(/_+$/, "") || "question";
|
|
11
|
+
const takenSet = new Set(taken);
|
|
12
|
+
let qid = base;
|
|
13
|
+
let n = 1;
|
|
14
|
+
while (takenSet.has(qid)) {
|
|
15
|
+
n += 1;
|
|
16
|
+
qid = `${base}_${n}`;
|
|
17
|
+
}
|
|
18
|
+
return qid;
|
|
19
|
+
}
|
|
20
|
+
export class Sense {
|
|
21
|
+
apiKey;
|
|
22
|
+
baseUrl;
|
|
23
|
+
model;
|
|
24
|
+
hz;
|
|
25
|
+
transport;
|
|
26
|
+
questions = [];
|
|
27
|
+
whens = [];
|
|
28
|
+
waveHandlers = [];
|
|
29
|
+
constructor(opts = {}) {
|
|
30
|
+
this.apiKey = opts.apiKey ?? process.env.SENSE_API_KEY;
|
|
31
|
+
this.baseUrl = opts.baseUrl ?? process.env.SENSE_BASE_URL;
|
|
32
|
+
this.model = opts.model ?? Session.DEFAULT_MODEL;
|
|
33
|
+
this.hz = opts.hz ?? 25;
|
|
34
|
+
this.transport = opts.transport ?? "auto";
|
|
35
|
+
}
|
|
36
|
+
/** Register a binary question. TEXT-FIRST like the python facade: the
|
|
37
|
+
* natural-language question is the first argument; the id is optional and
|
|
38
|
+
* auto-slugged from the question text (options optional; the server
|
|
39
|
+
* defaults to true/false). */
|
|
40
|
+
noul(question, opts = {}) {
|
|
41
|
+
return this.register({ id: this.qid(question, opts.id), kind: "noul", prompt: question, options: opts.options });
|
|
42
|
+
}
|
|
43
|
+
/** Register an n-way choice question (text-first; id auto-slugs). */
|
|
44
|
+
choice(question, options, opts = {}) {
|
|
45
|
+
return this.register({ id: this.qid(question, opts.id), kind: "choice", prompt: question, options });
|
|
46
|
+
}
|
|
47
|
+
/** Register an ordinal score question, 2..10 levels (text-first; id auto-slugs). */
|
|
48
|
+
score(question, levels, opts = {}) {
|
|
49
|
+
return this.register({ id: this.qid(question, opts.id), kind: "score", prompt: question, levels });
|
|
50
|
+
}
|
|
51
|
+
/** Mirror of python `_qid`: the question text is required and non-empty;
|
|
52
|
+
* the id is auto-slugged from it when omitted and must be non-empty when
|
|
53
|
+
* given explicitly. */
|
|
54
|
+
qid(question, id) {
|
|
55
|
+
if (typeof question !== "string" || question.trim() === "") {
|
|
56
|
+
throw new Error("question text must be a non-empty string (text-first API)");
|
|
57
|
+
}
|
|
58
|
+
if (id === undefined)
|
|
59
|
+
return slug(question, this.questions.map((q) => q.id));
|
|
60
|
+
if (id.trim() === "")
|
|
61
|
+
throw new Error("explicit id must be non-empty");
|
|
62
|
+
return id;
|
|
63
|
+
}
|
|
64
|
+
register(init) {
|
|
65
|
+
const q = new Question(init);
|
|
66
|
+
const i = this.questions.findIndex((x) => x.id === q.id);
|
|
67
|
+
if (i >= 0)
|
|
68
|
+
this.questions[i] = q;
|
|
69
|
+
else
|
|
70
|
+
this.questions.push(q);
|
|
71
|
+
return q;
|
|
72
|
+
}
|
|
73
|
+
when(pred, handler) {
|
|
74
|
+
const handle = { pred, handler };
|
|
75
|
+
this.whens.push(handle);
|
|
76
|
+
return {
|
|
77
|
+
cancel: () => {
|
|
78
|
+
this.whens = this.whens.filter((h) => h !== handle);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Observe waves on every session opened from here; `coalesce` skips
|
|
83
|
+
* consecutive same-argmax waves (latest wins). */
|
|
84
|
+
onWave(handler, opts = {}) {
|
|
85
|
+
const entry = { handler, opts };
|
|
86
|
+
this.waveHandlers.push(entry);
|
|
87
|
+
return {
|
|
88
|
+
cancel: () => {
|
|
89
|
+
this.waveHandlers = this.waveHandlers.filter((h) => h !== entry);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Open a session carrying the questions and handlers registered here. */
|
|
94
|
+
session() {
|
|
95
|
+
const s = new Session({
|
|
96
|
+
apiKey: this.apiKey,
|
|
97
|
+
baseUrl: this.baseUrl,
|
|
98
|
+
model: this.model,
|
|
99
|
+
hz: this.hz,
|
|
100
|
+
transport: this.transport,
|
|
101
|
+
questions: this.questions,
|
|
102
|
+
});
|
|
103
|
+
for (const { pred, handler } of this.whens)
|
|
104
|
+
s.when(pred, handler);
|
|
105
|
+
for (const { handler, opts } of this.waveHandlers)
|
|
106
|
+
s.onWave(handler, opts);
|
|
107
|
+
return s;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Transport, WireDialer } from "./transport.js";
|
|
2
|
+
import { Question } from "./question.js";
|
|
3
|
+
import type { QuestionInit, QuestionKind } from "./question.js";
|
|
4
|
+
import { Wave, type Result } from "./wave.js";
|
|
5
|
+
import { Context, type WaveHandler } from "./context.js";
|
|
6
|
+
import type { Predicate } from "./predicate.js";
|
|
7
|
+
export interface SessionEvent {
|
|
8
|
+
type: string;
|
|
9
|
+
code?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
raw: unknown;
|
|
12
|
+
}
|
|
13
|
+
/** Parse a server event object into the SDK's session-event shape. */
|
|
14
|
+
export declare function sessionEvent(raw: unknown): SessionEvent;
|
|
15
|
+
export interface SessionOptions {
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
model?: string;
|
|
19
|
+
hz?: number;
|
|
20
|
+
questions?: Question[];
|
|
21
|
+
/** Wire transport: "auto" = quic → webrtc → ws (default). */
|
|
22
|
+
transport?: Transport;
|
|
23
|
+
/** @internal test seam: override the wire dialer. */
|
|
24
|
+
wireFactory?: WireDialer;
|
|
25
|
+
}
|
|
26
|
+
export declare class Session {
|
|
27
|
+
static readonly DEFAULT_BASE_URL = "wss://inference.urun.sh";
|
|
28
|
+
static readonly DEFAULT_MODEL = "sense-latest:bf16";
|
|
29
|
+
readonly apiKey: string;
|
|
30
|
+
readonly baseUrl: string;
|
|
31
|
+
readonly model: string;
|
|
32
|
+
readonly hz: number;
|
|
33
|
+
readonly transport: Transport;
|
|
34
|
+
readonly context: Context;
|
|
35
|
+
readonly audio: AudioInput;
|
|
36
|
+
readonly video: VideoInput;
|
|
37
|
+
readonly text: TextInput;
|
|
38
|
+
readonly stats: {
|
|
39
|
+
waves: number;
|
|
40
|
+
turns: number;
|
|
41
|
+
errors: number;
|
|
42
|
+
reconnects: number;
|
|
43
|
+
decisions: number;
|
|
44
|
+
protocolErrors: number;
|
|
45
|
+
};
|
|
46
|
+
private isClosed;
|
|
47
|
+
private wire;
|
|
48
|
+
private readonly wireFactory;
|
|
49
|
+
private waveSeq;
|
|
50
|
+
private sourceQueues;
|
|
51
|
+
private rrCursor;
|
|
52
|
+
private oneShotText;
|
|
53
|
+
private transcript;
|
|
54
|
+
private waveQueue;
|
|
55
|
+
private waveWaiters;
|
|
56
|
+
private accumulator;
|
|
57
|
+
private accTMs;
|
|
58
|
+
private turnOpen;
|
|
59
|
+
private audioPending;
|
|
60
|
+
private inputSinceTurn;
|
|
61
|
+
private registry;
|
|
62
|
+
private eventListeners;
|
|
63
|
+
constructor(opts?: SessionOptions);
|
|
64
|
+
get questions(): Question[];
|
|
65
|
+
get closed(): boolean;
|
|
66
|
+
/** Register (or replace) a question; takes effect at the next turn open. */
|
|
67
|
+
addQuestion(id: string, kind: QuestionKind, opts?: Omit<QuestionInit, "id" | "kind">): Question;
|
|
68
|
+
private addQuestionRaw;
|
|
69
|
+
realtimeUrl(): string;
|
|
70
|
+
/** @internal */
|
|
71
|
+
emitAudio(b64: string, source?: string): void;
|
|
72
|
+
/** ponytail: round-robin one queued non-default chunk per default push (PR-2
|
|
73
|
+
* degradation); replace with labeled lanes when PR-2 lands. */
|
|
74
|
+
private drainSourceQueues;
|
|
75
|
+
/** @internal */
|
|
76
|
+
emitVideo(jpeg: Uint8Array): void;
|
|
77
|
+
/** @internal */
|
|
78
|
+
emitText(text: string, mode: string): void;
|
|
79
|
+
private sendJson;
|
|
80
|
+
private sendSessionUpdate;
|
|
81
|
+
private openTurn;
|
|
82
|
+
/** Barge-in: stop the active turn's cadence. */
|
|
83
|
+
bargeIn(): void;
|
|
84
|
+
/** Connect with the §7 dial policy (503/429 → backoff and redial). The
|
|
85
|
+
* transport selection (auto: quic → webrtc → ws) happens in the wire
|
|
86
|
+
* factory; a refused dial restarts the whole order. */
|
|
87
|
+
connect(): Promise<void>;
|
|
88
|
+
private onClose;
|
|
89
|
+
private onMessage;
|
|
90
|
+
private onDeltaMessage;
|
|
91
|
+
private onTurnCompleted;
|
|
92
|
+
/** Returns true when the error was handled locally and needs no listener dispatch. */
|
|
93
|
+
private onErrorMessage;
|
|
94
|
+
onEvent(handler: (ev: SessionEvent) => void): {
|
|
95
|
+
cancel(): void;
|
|
96
|
+
};
|
|
97
|
+
/** §6.3 client-side wave assembly: one decision line per question per wave;
|
|
98
|
+
* a repeat qid closes the previous wave. */
|
|
99
|
+
private onDecisionLine;
|
|
100
|
+
private flushAccumulator;
|
|
101
|
+
private deliver;
|
|
102
|
+
private nextWave;
|
|
103
|
+
/** Async-iterator of waves: push any given inputs, then run the turn loop. */
|
|
104
|
+
run(inputs?: Iterable<InputFrame> | AsyncIterable<InputFrame>): AsyncGenerator<Wave>;
|
|
105
|
+
private applyFrame;
|
|
106
|
+
/** Latest result for a question, or null before the first wave. */
|
|
107
|
+
latest(question: string): Result | null;
|
|
108
|
+
/** Iterate waves live; coalesce drops earlier waves in runs of identical
|
|
109
|
+
* argmax values (latest wins). */
|
|
110
|
+
waves(opts?: {
|
|
111
|
+
coalesce?: boolean;
|
|
112
|
+
}): AsyncGenerator<Wave>;
|
|
113
|
+
when(pred: Predicate, handler: WaveHandler): {
|
|
114
|
+
cancel(): void;
|
|
115
|
+
};
|
|
116
|
+
/** Observe waves live; `coalesce` delivers the FIRST wave of a run of
|
|
117
|
+
* consecutive same-argmax waves — later waves update `latest()` without
|
|
118
|
+
* another callback. */
|
|
119
|
+
onWave(handler: WaveHandler, opts?: {
|
|
120
|
+
coalesce?: boolean;
|
|
121
|
+
}): {
|
|
122
|
+
cancel(): void;
|
|
123
|
+
};
|
|
124
|
+
close(): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
export type InputFrame = {
|
|
127
|
+
audio: Uint8Array | ArrayBuffer;
|
|
128
|
+
source?: string;
|
|
129
|
+
} | {
|
|
130
|
+
video: Uint8Array | ArrayBuffer;
|
|
131
|
+
} | {
|
|
132
|
+
text: string;
|
|
133
|
+
mode?: "append" | "replace" | "event";
|
|
134
|
+
};
|
|
135
|
+
export declare class AudioInput {
|
|
136
|
+
private session;
|
|
137
|
+
constructor(session: Session);
|
|
138
|
+
/** Push PCM16 24 kHz mono (encoded base64 on the wire). */
|
|
139
|
+
push(pcm: Uint8Array | ArrayBuffer, source?: string): void;
|
|
140
|
+
}
|
|
141
|
+
export declare class VideoInput {
|
|
142
|
+
private session;
|
|
143
|
+
constructor(session: Session);
|
|
144
|
+
push(jpeg: Uint8Array | ArrayBuffer): void;
|
|
145
|
+
}
|
|
146
|
+
export type TextMode = "append" | "replace" | "event";
|
|
147
|
+
export declare class TextInput {
|
|
148
|
+
private session;
|
|
149
|
+
constructor(session: Session);
|
|
150
|
+
push(text: string, mode?: TextMode): void;
|
|
151
|
+
}
|