package whisperx import ( "context" "path/filepath" "gitea.maximumdirect.net/eric/narratio/internal/fileops" ) var minimalTranscriptJSON = []byte(`{"schema":"speaker_transcript.v1","segments":[]}`) // NoopClient is a deterministic no-op WhisperX adapter. type NoopClient struct{} // Transcribe returns the requested output path with placeholder metadata. func (n *NoopClient) Transcribe(ctx context.Context, req TranscribeRequest) (TranscribeResult, error) { if err := ctx.Err(); err != nil { return TranscribeResult{}, err } if err := writeMinimalJSON(req.OutputRawTranscriptPath); err != nil { return TranscribeResult{}, err } return TranscribeResult{ OutputRawTranscriptPath: req.OutputRawTranscriptPath, Attempts: 1, HTTPStatus: 200, Metadata: map[string]any{ "placeholder": true, }, }, nil } // FakeClient captures requests and returns deterministic responses for tests. type FakeClient struct { Requests []TranscribeRequest Err error Result TranscribeResult TranscribeFn func(ctx context.Context, req TranscribeRequest) (TranscribeResult, error) } // Transcribe records the request and returns either configured error or result. func (f *FakeClient) Transcribe(ctx context.Context, req TranscribeRequest) (TranscribeResult, error) { if err := ctx.Err(); err != nil { return TranscribeResult{}, err } f.Requests = append(f.Requests, req) if f.TranscribeFn != nil { return f.TranscribeFn(ctx, req) } if f.Err != nil { return TranscribeResult{}, f.Err } res := f.Result if res.OutputRawTranscriptPath == "" { res.OutputRawTranscriptPath = req.OutputRawTranscriptPath } if res.Attempts == 0 { res.Attempts = 1 } if res.Metadata == nil { res.Metadata = map[string]any{"fake": true} } if err := writeMinimalJSON(res.OutputRawTranscriptPath); err != nil { return TranscribeResult{}, err } return res, nil } func writeMinimalJSON(path string) error { if path == "" { return nil } if err := fileops.EnsureWorkspaceDirectory(filepath.Dir(path)); err != nil { return err } return fileops.WriteFileAtomic(path, minimalTranscriptJSON, fileops.WorkspaceFileMode) }