fix(uploads): a file much shorter than it claimed is transcribed and noted, not refused; the tolerances are named (second review finding 1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
+29
-14
@@ -275,11 +275,18 @@ func (w *Worker) Process(ctx context.Context, job Job) {
|
|||||||
abort(domain.UploadErrTranscriptionFailed)
|
abort(domain.UploadErrTranscriptionFailed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if kind, bad := w.audioLengthProblem(wav, job.Duration); bad {
|
got, tooLong := w.audioLengthProblem(wav)
|
||||||
abort(kind)
|
if tooLong {
|
||||||
log.Error("upload: converted audio length rejected", "kind", string(kind))
|
abort(domain.UploadErrTooLong)
|
||||||
|
log.Error("upload: converted audio is over the limit", "audio_s", int(got.Seconds()), "limit_s", int(w.maxDuration.Seconds()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if w.maxDuration > 0 && job.Duration > 0 {
|
||||||
|
if note := shortfallNote(got, job.Duration); note != "" {
|
||||||
|
log.Warn("upload: audio is much shorter than the file claimed", "audio_s", int(got.Seconds()), "claimed_s", int(job.Duration.Seconds()))
|
||||||
|
tr.Annotate("audio", note)
|
||||||
|
}
|
||||||
|
}
|
||||||
tr.Done("audio")
|
tr.Done("audio")
|
||||||
|
|
||||||
if !planned {
|
if !planned {
|
||||||
@@ -343,21 +350,29 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// audioLengthProblem measures the converted WAV (16 kHz mono 16-bit PCM is 32,000 bytes a
|
// audioLengthProblem measures the converted WAV (16 kHz mono 16-bit PCM is 32,000 bytes a
|
||||||
// second after a 44-byte header) against the limit and against what the file claimed.
|
// second after a 44-byte header) against the limit. It returns the real length and whether
|
||||||
func (w *Worker) audioLengthProblem(wav string, claimed time.Duration) (domain.UploadErrorKind, bool) {
|
// that is over the limit by more than the tolerance.
|
||||||
|
func (w *Worker) audioLengthProblem(wav string) (got time.Duration, tooLong bool) {
|
||||||
if w.maxDuration <= 0 {
|
if w.maxDuration <= 0 {
|
||||||
return "", false
|
return 0, false
|
||||||
}
|
}
|
||||||
info, err := os.Stat(wav)
|
info, err := os.Stat(wav)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return 0, false
|
||||||
}
|
}
|
||||||
got := time.Duration(float64(max(info.Size()-44, 0)) / 32000 * float64(time.Second))
|
got = time.Duration(float64(max(info.Size()-44, 0)) / 32000 * float64(time.Second))
|
||||||
switch {
|
return got, got > w.maxDuration+tooLongSlack
|
||||||
case got > w.maxDuration+tooLongSlack:
|
}
|
||||||
return domain.UploadErrTooLong, true
|
|
||||||
case float64(got) < incompleteBelow*float64(claimed) && claimed-got > incompleteShortfall:
|
// shortfallNote is a remark for the audio step when the converted audio is much shorter
|
||||||
return domain.UploadErrIncomplete, true
|
// than the file claimed, or "" when it is not. It is a NOTE and never a failure: a
|
||||||
|
// container header can over-estimate a complete file (a variable-bitrate MP3 without a Xing
|
||||||
|
// header claimed 79 minutes for 20 real ones), so refusing would turn away real
|
||||||
|
// recordings, while saying nothing about a truncated one would hide a partial transcript.
|
||||||
|
func shortfallNote(got, claimed time.Duration) string {
|
||||||
|
if float64(got) >= incompleteBelow*float64(claimed) || claimed-got <= incompleteShortfall {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return "", false
|
return fmt.Sprintf("The audio is %s long; the file claimed %s. If the recording was cut off, upload the complete one.",
|
||||||
|
FormatDuration(got), FormatDuration(claimed))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user