import { randomUUID } from "crypto"; import type { TranscriptionJob, SrtSegment, Anomaly, JobStatus, CorrectionRequest } from "@shared/schema"; export interface IStorage { createJob(fileName: string, fileSize: number, fileType: string, userContext?: string): Promise; getJob(id: string): Promise; updateJobStatus(id: string, status: JobStatus, progress?: number): Promise; updateJobError(id: string, errorMessage: string): Promise; setJobSegments(id: string, segments: SrtSegment[]): Promise; setJobAnomalies(id: string, anomalies: Anomaly[]): Promise; applyCorrection(jobId: string, anomalyId: string, correction: string): Promise; applySimilarCorrections(jobId: string, flaggedText: string, correction: string): Promise; updateSegmentText(jobId: string, segmentId: number, newText: string): Promise; } export class MemStorage implements IStorage { private jobs: Map; constructor() { this.jobs = new Map(); } async createJob( fileName: string, fileSize: number, fileType: string, userContext?: string, localFilePath?: string ): Promise { const id = randomUUID(); const job: TranscriptionJob = { id, fileName, fileSize, fileType: (fileType || "audio/mpeg") as "mp3" | "mp4" | "audio/mpeg" | "audio/mp3" | "video/mp4", status: "pending", progress: 0, userContext, mediaUrl: `/api/jobs/${id}/media`, createdAt: new Date().toISOString(), }; // Store local path internally (not in schema) (job as any).localFilePath = localFilePath; this.jobs.set(id, job); return job; } async getJob(id: string): Promise { return this.jobs.get(id); } async updateJobStatus(id: string, status: JobStatus, progress?: number): Promise { const job = this.jobs.get(id); if (job) { job.status = status; if (progress !== undefined) { job.progress = progress; } if (status === "completed") { job.completedAt = new Date().toISOString(); } this.jobs.set(id, job); } } async updateJobError(id: string, errorMessage: string): Promise { const job = this.jobs.get(id); if (job) { job.status = "failed"; job.errorMessage = errorMessage; this.jobs.set(id, job); } } async setJobSegments(id: string, segments: SrtSegment[]): Promise { const job = this.jobs.get(id); if (job) { job.segments = segments; this.jobs.set(id, job); } } async setJobAnomalies(id: string, anomalies: Anomaly[]): Promise { const job = this.jobs.get(id); if (job) { job.anomalies = anomalies; this.jobs.set(id, job); } } async applyCorrection(jobId: string, anomalyId: string, correction: string): Promise { const job = this.jobs.get(jobId); if (!job || !job.anomalies || !job.segments) return; const anomaly = job.anomalies.find(a => a.id === anomalyId); if (!anomaly) return; // Update the anomaly anomaly.resolved = true; anomaly.userCorrection = correction; // Update the segment text const segment = job.segments.find(s => s.id === anomaly.segmentId); if (segment) { segment.text = segment.text.replace(anomaly.flaggedText, correction); } this.jobs.set(jobId, job); } async applySimilarCorrections(jobId: string, flaggedText: string, correction: string): Promise { const job = this.jobs.get(jobId); if (!job || !job.anomalies || !job.segments) return 0; let correctionCount = 0; const lowerFlaggedText = flaggedText.toLowerCase(); for (const anomaly of job.anomalies) { if (!anomaly.resolved && anomaly.flaggedText.toLowerCase() === lowerFlaggedText) { anomaly.resolved = true; anomaly.userCorrection = correction; correctionCount++; // Update the segment text const segment = job.segments.find(s => s.id === anomaly.segmentId); if (segment) { segment.text = segment.text.replace(anomaly.flaggedText, correction); } } } this.jobs.set(jobId, job); return correctionCount; } async updateSegmentText(jobId: string, segmentId: number, newText: string): Promise { const job = this.jobs.get(jobId); if (!job || !job.segments) return; const segment = job.segments.find(s => s.id === segmentId); if (segment) { segment.text = newText; this.jobs.set(jobId, job); } } } export const storage = new MemStorage();