67 lines
1.6 KiB
TypeScript
67 lines
1.6 KiB
TypeScript
import { requestTranscription } from "#lib/api/media.js";
|
|
import { t } from "#lib/i18n/locale.svelte.js";
|
|
import type { MessageKey } from "#lib/i18n/messages.js";
|
|
|
|
const REFUSALS: Record<string, MessageKey> = {
|
|
empty: "media.transcribeEmpty",
|
|
no_premium: "media.transcribeNoPremium",
|
|
pending: "media.transcribePending",
|
|
too_long: "media.transcribeTooLong",
|
|
};
|
|
|
|
export class Transcript {
|
|
readonly #chatId: () => number;
|
|
readonly #messageId: () => number;
|
|
readonly #initial: () => string | null;
|
|
failure = $state<string | null>(null);
|
|
fetched = $state<string | null>(null);
|
|
pending = $state(false);
|
|
shown = $state(false);
|
|
|
|
constructor(
|
|
chatId: () => number,
|
|
messageId: () => number,
|
|
initial: () => string | null
|
|
) {
|
|
this.#chatId = chatId;
|
|
this.#messageId = messageId;
|
|
this.#initial = initial;
|
|
}
|
|
|
|
get text(): string | null {
|
|
return this.fetched ?? this.#initial();
|
|
}
|
|
|
|
get open(): boolean {
|
|
return this.shown && Boolean(this.text);
|
|
}
|
|
|
|
async toggle(): Promise<void> {
|
|
if (this.text) {
|
|
this.shown = !this.shown;
|
|
return;
|
|
}
|
|
if (this.pending) {
|
|
return;
|
|
}
|
|
this.pending = true;
|
|
this.failure = null;
|
|
try {
|
|
const outcome = await requestTranscription(
|
|
this.#chatId(),
|
|
this.#messageId()
|
|
);
|
|
if ("text" in outcome) {
|
|
this.fetched = outcome.text;
|
|
this.shown = true;
|
|
} else {
|
|
this.failure = t(REFUSALS[outcome.error] ?? "media.transcribeFailed");
|
|
}
|
|
} catch {
|
|
this.failure = t("media.transcribeFailed");
|
|
} finally {
|
|
this.pending = false;
|
|
}
|
|
}
|
|
}
|