File size: 2,535 Bytes
96f2542 8122b04 96f2542 8122b04 96f2542 8122b04 96f2542 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | import Dexie, { type Table } from "dexie";
export const HISTORY_CAP = 50;
export type VoiceRecord = {
id?: number;
name: string;
blob: Blob;
sampleRate: number;
durationMs: number;
createdAt: number;
isFavorite: boolean;
};
export type SpeakerRef = { letter: "A" | "B" | "C" | "D"; voiceId: number };
export type HistoryRecord = {
id?: number;
text: string;
modelId: string;
voiceId?: number;
language?: string;
params: Record<string, unknown>;
audioBlob: Blob;
createdAt: number;
kind?: "single" | "dialog";
seedUsed?: number;
speakers?: SpeakerRef[];
};
class DB extends Dexie {
voices!: Table<VoiceRecord, number>;
history!: Table<HistoryRecord, number>;
constructor() {
super("chatterbox-voice-studio");
this.version(1).stores({
voices: "++id, name, createdAt, isFavorite",
history: "++id, createdAt",
});
this.version(2).stores({
voices: "++id, name, createdAt, isFavorite",
history: "++id, createdAt",
}).upgrade(async (tx) => {
// Backfill new fields on existing rows so listings stay consistent.
await tx.table("history").toCollection().modify((r: HistoryRecord) => {
if (!r.kind) r.kind = "single";
});
});
}
}
export const db = new DB();
export async function addVoice(
v: Omit<VoiceRecord, "id" | "createdAt" | "isFavorite"> & Partial<Pick<VoiceRecord, "isFavorite">>,
): Promise<number> {
return db.voices.add({
...v,
isFavorite: v.isFavorite ?? false,
createdAt: Date.now(),
});
}
export async function listVoices(): Promise<VoiceRecord[]> {
return db.voices.orderBy("createdAt").reverse().toArray();
}
export async function deleteVoice(id: number): Promise<void> {
await db.voices.delete(id);
}
export async function setFavorite(id: number, fav: boolean): Promise<void> {
await db.voices.update(id, { isFavorite: fav });
}
export async function addHistory(
h: Omit<HistoryRecord, "id" | "createdAt">,
): Promise<number> {
const id = await db.history.add({ ...h, createdAt: Date.now() });
const count = await db.history.count();
if (count > HISTORY_CAP) {
const overflow = count - HISTORY_CAP;
const oldest = await db.history.orderBy("createdAt").limit(overflow).primaryKeys();
await db.history.bulkDelete(oldest);
}
return id;
}
export async function listHistory(): Promise<HistoryRecord[]> {
return db.history.orderBy("createdAt").reverse().toArray();
}
export async function clearHistory(): Promise<void> {
await db.history.clear();
}
|