import 'dotenv/config';
import { AssemblyAI } from 'assemblyai';
let instance: AssemblyAI | null = null;
export function getClient(): AssemblyAI {
if (!instance) {
if (!process.env.ASSEMBLYAI_API_KEY) {
throw new Error('ASSEMBLYAI_API_KEY not set. Copy .env.example to .env.local');
}
instance = new AssemblyAI({
apiKey: process.env.ASSEMBLYAI_API_KEY,
});
}
return instance;
}
import fs from 'fs';
import path from 'path';
import { getClient } from './client';
import type { Transcript } from 'assemblyai';
const CACHE_DIR = path.join(process.cwd(), '.assemblyai-cache');
export async function transcribeWithCache(
audioUrl: string,
options: Record<string, any> = {}
): Promise<Transcript> {
const cacheKey = Buffer.from(audioUrl + JSON.stringify(options))
.toString('base64url')
.slice(0, 32);
const cachePath = path.join(CACHE_DIR, `${cacheKey}.json`);
if (process.env.NODE_ENV !== 'production' && fs.existsSync(cachePath)) {
console.log('[dev] Using cached transcript:', cacheKey);
return JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
}
const client = getClient();
const transcript = await client.transcripts.transcribe({
audio: audioUrl,
...options,
});
fs.mkdirSync(CACHE_DIR, { recursive: true });
fs.writeFileSync(cachePath, JSON.stringify(transcript, null, 2));
console.log('[dev] Cached transcript:', cacheKey);
return transcript;
}
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AssemblyAI } from 'assemblyai';
vi.mock('assemblyai', () => ({
AssemblyAI: vi.fn().mockImplementation(() => ({
transcripts: {
transcribe: vi.fn().mockResolvedValue({
id: 'test-transcript-id',
status: 'completed',
text: 'This is a test transcript.',
audio_duration: 30,
words: [
{ text: 'This', start: 0, end: 200, confidence: 0.99 },
{ text: 'is', start: 210, end: 350, confidence: 0.98 },
],
}),
get: vi.fn(),
list: vi.fn(),
},
lemur: {
task: vi.fn().mockResolvedValue({
request_id: 'test-lemur-id',
response: 'Test summary of the audio.',
}),
},
})),
}));
describe('Transcription', () => {
it('should transcribe audio and return text', async () => {
const client = new AssemblyAI({ apiKey: 'test-key' });
const result = await client.transcripts.transcribe({
audio: 'https://example.com/audio.wav',
});
expect(result.status).toBe('completed');
expect(result.text).toContain('test transcript');
expect(result.words).toHaveLength(2);
});
it('should run LeMUR task on transcript', async () => {
const client = new AssemblyAI({ apiKey: 'test-key' });
const { response } = await client.lemur.task({
transcript_ids: ['test-transcript-id'],
prompt: 'Summarize this.',
});
expect(response).toContain('summary');
});
});