Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ ASSEMBLYAI_API_KEY=""
ELEVENLABS_API_KEY=""
SPEECHMATICS_API_KEY=""
MISTRAL_API_KEY=""
SMALLEST_API_KEY=""
1 change: 1 addition & 0 deletions prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const providers = [
{ name: "AssemblyAI", slug: "assemblyai", logoUrl: "/providers/assemblyai.svg" },
{ name: "Speechmatics", slug: "speechmatics", logoUrl: "/providers/speechmatics.svg" },
{ name: "Mistral", slug: "mistral", logoUrl: "/providers/mistral.svg" },
{ name: "Smallest AI", slug: "smallest", logoUrl: "/providers/smallest.svg" },
];

const removedSlugs = ["soniox", "openai-whisper"];
Expand Down
18 changes: 18 additions & 0 deletions public/providers/smallest.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/lib/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const PROVIDERS: ProviderDef[] = [
{ name: "AssemblyAI", slug: "assemblyai", logoUrl: "/providers/assemblyai.svg", color: "#0055FF", model: "Universal-3 Pro" },
{ name: "Speechmatics", slug: "speechmatics", logoUrl: "/providers/speechmatics.svg", color: "#FF3D00", model: "Enhanced" },
{ name: "Mistral", slug: "mistral", logoUrl: "/providers/mistral.svg", color: "#FF7000", model: "Voxtral Mini" },
{ name: "Smallest AI", slug: "smallest", logoUrl: "/providers/smallest.svg", color: "#1D4E52", model: "Pulse" },
];

export function getProviderBySlug(slug: string): ProviderDef | undefined {
Expand Down
60 changes: 60 additions & 0 deletions src/lib/providers/smallest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { TranscribeResult, WordTimestamp } from "../transcribe";

const SMALLEST_BASE = "https://api.smallest.ai/waves/v1/stt";

interface SmallestWord {
word: string;
start: number;
end: number;
confidence?: number;
}

interface SmallestResponse {
status: string;
transcription?: string;
words?: SmallestWord[];
}

export async function transcribeWithSmallest(
audio: Buffer,
_mimeType: string
): Promise<TranscribeResult> {
const apiKey = process.env.SMALLEST_API_KEY;
if (!apiKey) throw new Error("SMALLEST_API_KEY not set");

const start = Date.now();

const url = new URL(SMALLEST_BASE);
url.searchParams.set("model", "pulse");
url.searchParams.set("word_timestamps", "true");

const response = await fetch(url.toString(), {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/octet-stream",
},
body: audio,
});

if (!response.ok) {
const body = await response.text();
throw new Error(`HTTP ${response.status}: Smallest AI request failed: ${body}`);
}
Comment thread
harshitajain165 marked this conversation as resolved.

const data: SmallestResponse = await response.json();

const words: WordTimestamp[] = (data.words || []).map((w) => ({
word: w.word,
start: w.start,
end: w.end,
}));

const durationMs = Date.now() - start;

return {
transcript: data.transcription ?? "",
words,
durationMs,
};
}
3 changes: 3 additions & 0 deletions src/lib/transcribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { transcribeWithAssemblyAI } from "./providers/assemblyai";
import { transcribeWithElevenLabs } from "./providers/elevenlabs";
import { transcribeWithSpeechmatics } from "./providers/speechmatics";
import { transcribeWithMistral } from "./providers/mistral";
import { transcribeWithSmallest } from "./providers/smallest";

export interface WordTimestamp {
word: string;
Expand All @@ -28,6 +29,7 @@ const PROVIDER_MAP: Record<string, TranscribeFn | undefined> = {
elevenlabs: transcribeWithElevenLabs,
speechmatics: transcribeWithSpeechmatics,
mistral: transcribeWithMistral,
smallest: transcribeWithSmallest,
};

const MAX_RETRIES = 2;
Expand Down Expand Up @@ -151,6 +153,7 @@ function sanitizeError(message: string, slug: string): string {
elevenlabs: "ElevenLabs",
speechmatics: "Speechmatics",
mistral: "Mistral",
smallest: "Smallest AI",
};

const name = providerNames[slug] || slug;
Expand Down