stt-sdk
Version:
基于 LLMs 的语音转文本 SDK
182 lines (149 loc) • 4.8 kB
text/typescript
import { BaseSTTClientHookType, STT_VOICE_STOP, type BaseSTTClient } from "../base/BaseSTTClient.js";
type ConfigOf<C> = C extends BaseSTTClient<infer X> ? X : never;
/**
* STS 应用
*/
export class STTApplication<Cfg = never> {
/**
* 单例模式
*/
private static singleton: STTApplication | null = null;
/**
* 客户端实例
*/
private client: BaseSTTClient<Cfg> | null = null;
/**
* token 获取钩子
*/
private tokenGetHook: (() => Promise<string>) | null = null;
/**
* 工厂函数
*/
public static of(need_new?: boolean) {
if (need_new) return new STTApplication();
return STTApplication.singleton ?? (STTApplication.singleton = new STTApplication());
}
/**
* 转译模式设置
* @param is_real 是否实时转译?
*/
public setTranslationMode(is_real?: boolean) {
if (!this.client) {
throw new Error("客户端未注入");
}
this.client.setMode(is_real ? "rt" : "all");
return this;
}
/**
* 客户端注入
* @param CC 客户端实现类(构造函数)
*/
public clientInject<C extends BaseSTTClient<any>>(
CC: new () => C
): STTApplication<ConfigOf<C>> {
// 复用当前实例也可以,这里演示就地赋值 + 类型收窄返回
(this as any).client = new CC() as BaseSTTClient<ConfigOf<C>>;
return this as unknown as STTApplication<ConfigOf<C>>;
}
/**
* token 获取钩子
*/
public addTokenGetHook(token_or_func: string | (() => Promise<string>)) {
if (!this.client) {
throw new Error("客户端未注入");
}
if (typeof token_or_func === "string") {
this.client.setAccessToken(token_or_func);
} else {
this.tokenGetHook = async () => {
return await token_or_func();
}
}
return this;
}
/**
* 转译文本接收钩子
*/
public addTextReceiveHook(func: (text: string) => void) {
if (!this.client) {
throw new Error("客户端未注入");
}
this.client.addHook(BaseSTTClientHookType.TEXT_RECEIVE, async (text: string) => func(text));
return this;
}
/**
* 客户端配置钩子
*/
public setupClientConfig(config: Cfg) {
if (!this.client) {
throw new Error("客户端未注入");
}
this.client.setClientConfig(config);
return this; // 保持链式
}
/**
* 连接关闭钩子函数
*/
public addConnectCloseHook(func: () => void) {
if (!this.client) {
throw new Error("客户端未注入");
}
this.client.addHook(BaseSTTClientHookType.CONNECT_CLOSE_HANDLE, async () => func());
return this;
}
/**
* 连接错误钩子函数
*/
public addConnecErrorHook(func: (e?: any) => void) {
if (!this.client) {
throw new Error("客户端未注入");
}
this.client.addHook(BaseSTTClientHookType.CONNECT_ERROR_HANDLE, async (e) => func(e));
return this;
}
/**
* 音频输入设备获取授权失败钩子函数
*/
public addOpenDeviceFailHook(func: (e?: any) => void) {
if (!this.client) {
throw new Error("客户端未注入");
}
this.client.addHook(BaseSTTClientHookType.DEVICE_OPEN_FAIL_HANDLE, async (e) => func(e));
return this;
}
/**
* 开始转译
*/
public start() {
if (!this.client) {
throw new Error("客户端未注入");
}
// hook 校验
this.client.checkRequiredHookIsAllRegister();
(async (context) => {
if (!context || !context.client) throw new Error("客户端未知错误");
if (context.tokenGetHook) {
const token = await context.tokenGetHook();
context.client.setAccessToken(token);
}
// 初始化连接
context.client.onConnectInit();
// 打开连接
context.client.onConnectOpen();
// 接收文本
context.client.onTextReceive();
})(this);
return this;
}
/**
* 结束转译
*/
public stop() {
if (!this.client) {
throw new Error("客户端未注入");
}
const event = new CustomEvent(STT_VOICE_STOP);
window.dispatchEvent(event);
this.client.closeConnection();
}
}