import { FastifyInstance } from "fastify"; import { VoiceEnrollmentService } from "@shieldai/voiceprint"; import { AnalysisService } from "@shieldai/voiceprint"; import { BatchAnalysisService } from "@shieldai/voiceprint"; export function voiceprintRoutes(fastify: FastifyInstance) { const enrollmentService = new VoiceEnrollmentService(); const analysisService = new AnalysisService(); const batchService = new BatchAnalysisService(); fastify.post("/enroll", async (request, reply) => { const userId = (request.user as { id: string })?.id; if (!userId) return reply.code(401).send({ error: "User not authenticated" }); const body = request.body as { label: string; audio: string; sampleRate?: number }; const audioBuffer = Buffer.from(body.audio, "base64"); const enrollment = await enrollmentService.enroll( { label: body.label, audioBuffer, sampleRate: body.sampleRate }, userId ); return reply.code(201).send(enrollment); }); fastify.get("/enrollments", async (request, reply) => { const userId = (request.user as { id: string })?.id; if (!userId) return reply.code(401).send({ error: "User not authenticated" }); const enrollments = await enrollmentService.listEnrollments(userId); return reply.send(enrollments); }); fastify.delete("/enrollments/:id", async (request, reply) => { const userId = (request.user as { id: string })?.id; if (!userId) return reply.code(401).send({ error: "User not authenticated" }); const enrollmentId = (request.params as { id: string }).id; const result = await enrollmentService.removeEnrollment(userId, enrollmentId); return reply.send({ removed: result }); }); fastify.post("/analyze", async (request, reply) => { const userId = (request.user as { id: string })?.id; if (!userId) return reply.code(401).send({ error: "User not authenticated" }); const body = request.body as { audio: string; sampleRate?: number; analysisType?: string }; const audioBuffer = Buffer.from(body.audio, "base64"); const result = await analysisService.analyze( { audioBuffer, sampleRate: body.sampleRate, analysisType: body.analysisType }, userId ); return reply.code(201).send(result); }); fastify.get("/results/:id", async (request, reply) => { const jobId = (request.params as { id: string }).id; const result = await analysisService.getResult(jobId); if (!result) return reply.code(404).send({ error: "Analysis result not found" }); return reply.send(result); }); fastify.get("/results", async (request, reply) => { const userId = (request.user as { id: string })?.id; if (!userId) return reply.code(401).send({ error: "User not authenticated" }); const limit = parseInt((request.query as { limit?: string }).limit || "20", 10); const results = await analysisService.getUserResults(userId, limit); return reply.send(results); }); fastify.post("/batch", async (request, reply) => { const userId = (request.user as { id: string })?.id; if (!userId) return reply.code(401).send({ error: "User not authenticated" }); const body = request.body as { files: Array<{ name: string; audio: string; sampleRate?: number }>; analysisType?: string; }; const audioBuffers = body.files.map((f) => ({ name: f.name, buffer: Buffer.from(f.audio, "base64"), sampleRate: f.sampleRate, })); const result = await batchService.analyzeBatch( { audioBuffers, analysisType: body.analysisType }, userId ); return reply.code(201).send(result); }); }