Carry the vocabulary hint as prompt from the engines through the worker into every window
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
99b9cd71cd
commit
313892b6df
@@ -37,6 +37,11 @@ export interface EngineTranscribeOptions {
|
||||
language?: string;
|
||||
/** transcribe | translate (multilingual models only). */
|
||||
task?: WhisperTask;
|
||||
/**
|
||||
* "Names and terms" vocabulary hint, raw user text (D-WS2a). Applies to
|
||||
* every Whisper model, `.en` ones included; empty/undefined = no prompt.
|
||||
*/
|
||||
prompt?: string;
|
||||
/**
|
||||
* Streaming transcript fragments — append each to the text shown so far.
|
||||
* Browser engine: token fragments; server engine: whole segments.
|
||||
@@ -140,6 +145,7 @@ export class BrowserEngine implements Engine {
|
||||
...(options.language !== undefined &&
|
||||
options.language !== "auto" && { language: options.language }),
|
||||
...(options.task !== undefined && { task: options.task }),
|
||||
...(options.prompt && { prompt: options.prompt }),
|
||||
};
|
||||
// Ownership of the audio moves to the worker — zero-copy transfer.
|
||||
this.worker.postMessage(message, [audio.buffer as ArrayBuffer]);
|
||||
@@ -282,6 +288,8 @@ export class ServerEngine implements Engine {
|
||||
params.set("language", options.language);
|
||||
}
|
||||
if (options.task !== undefined) params.set("task", options.task);
|
||||
// Validated + normalized server-side (parseLanguageAndTask, D-WS2a).
|
||||
if (options.prompt) params.set("prompt", options.prompt);
|
||||
|
||||
let response: Response;
|
||||
try {
|
||||
|
||||
@@ -17,6 +17,13 @@ import {
|
||||
type ProgressInfo,
|
||||
} from "@huggingface/transformers";
|
||||
import { resolveDefaultDtype } from "../lib/models";
|
||||
import {
|
||||
buildPromptPrefix,
|
||||
installPromptSupport,
|
||||
PROMPT_PREFIX_KWARG,
|
||||
type PromptableModel,
|
||||
type PromptTokenizer,
|
||||
} from "./prompt";
|
||||
import {
|
||||
deviceAttempts,
|
||||
dtypeRequiresF16,
|
||||
@@ -410,6 +417,17 @@ async function transcribe(message: TranscribeMessage): Promise<void> {
|
||||
if (message.task !== undefined) {
|
||||
options.task = message.task;
|
||||
}
|
||||
// "Names and terms" hint (D-WS2a): one prefix per pass, applied by the
|
||||
// generate() wrapper to every 30 s window (Transformers.js ignores
|
||||
// `prompt_ids`, see src/worker/prompt.ts). The wrapper is idempotent.
|
||||
const promptPrefix = buildPromptPrefix(
|
||||
asr.tokenizer as unknown as PromptTokenizer,
|
||||
message.prompt ?? "",
|
||||
);
|
||||
if (promptPrefix.length > 0) {
|
||||
installPromptSupport(asr.model as unknown as PromptableModel);
|
||||
options[PROMPT_PREFIX_KWARG] = promptPrefix;
|
||||
}
|
||||
|
||||
const output = await asr(message.audio, options);
|
||||
|
||||
|
||||
@@ -87,6 +87,13 @@ export interface TranscribeMessage {
|
||||
* engine (which correlates via requestId, D-010) still streams.
|
||||
*/
|
||||
stream?: boolean;
|
||||
/**
|
||||
* Optional "Names and terms" vocabulary hint, raw as the user typed it
|
||||
* (D-WS2a). The worker normalizes it, truncates it to Whisper's prompt
|
||||
* budget and feeds it as a decoder prompt to every window of this pass
|
||||
* (src/worker/prompt.ts). Empty/omitted = no prompt.
|
||||
*/
|
||||
prompt?: string;
|
||||
}
|
||||
|
||||
export type UiToWorkerMessage = LoadMessage | TranscribeMessage;
|
||||
@@ -318,7 +325,8 @@ export function isUiToWorkerMessage(value: unknown): value is UiToWorkerMessage
|
||||
value.task === "transcribe" ||
|
||||
value.task === "translate") &&
|
||||
isOptionalString(value.requestId) &&
|
||||
(value.stream === undefined || typeof value.stream === "boolean")
|
||||
(value.stream === undefined || typeof value.stream === "boolean") &&
|
||||
isOptionalString(value.prompt)
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user