Never double-import a file into the engine: detail Transcribe bails when the pump already owns the file (in-flight check was absent there — mid-upload the mapping sidecar doesn't exist yet, so the upload path created a second server recording; happened live with Gambino Tahoe 11-50). Pump's transcribeFile reuses an existing mapping via /reprocess instead of uploading fresh (a pipeline killed mid-run no longer re-imports as a new recording on next pump). Purged the 11:08 orphan recording from the engine DB.

This commit is contained in:
avi 2026-09-17 13:38:01 -05:00
commit 26f7b273ce

View file

@ -673,24 +673,39 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
return false return false
} }
return try { return try {
val draft = RecordingDraft( // If an earlier pass ever uploaded this file, reuse that
id = UUID.randomUUID().toString(), // recording and re-run the pipeline in place. Uploading again
title = f.nameWithoutExtension, // would create a duplicate server recording (this is exactly
createdAtEpochMs = f.lastModified().takeIf { it > 0 } // how a file whose pipeline died mid-run got re-imported as a
?: System.currentTimeMillis(), // second row on the next pump).
durationMs = 0, val existing = loadMapping(f)?.recordingId
mime = AUDIO_EXTS[f.extension.lowercase()] ?: "audio/mp4", val refKey: String
sourceFile = f, if (existing != null) {
sizeBytes = f.length(), refKey = existing
) runCatching {
val ref = provider.upload(draft) {} provider.reprocess(existing, "transcribe")
saveMapping(f, RemoteMapping(ref.key)) } // 409 "already running" is fine: we adopt it by polling.
} else {
val draft = RecordingDraft(
id = UUID.randomUUID().toString(),
title = f.nameWithoutExtension,
createdAtEpochMs = f.lastModified().takeIf { it > 0 }
?: System.currentTimeMillis(),
durationMs = 0,
mime = AUDIO_EXTS[f.extension.lowercase()] ?: "audio/mp4",
sourceFile = f,
sizeBytes = f.length(),
)
val ref = provider.upload(draft) {}
saveMapping(f, RemoteMapping(ref.key))
refKey = ref.key
}
var jobs: List<JobInfo> = emptyList() var jobs: List<JobInfo> = emptyList()
var polls = 0 var polls = 0
while (polls < 600) { // up to ~30 min per file at 2s polls while (polls < 600) { // up to ~30 min per file at 2s polls
polls++ polls++
delay(2000) delay(2000)
jobs = runCatching { parseJobs(provider.fetchJobs(ref.key)) }.getOrNull().orEmpty() jobs = runCatching { parseJobs(provider.fetchJobs(refKey)) }.getOrNull().orEmpty()
setLive(f.name, jobProgress(jobs)) setLive(f.name, jobProgress(jobs))
rescanStatuses() rescanStatuses()
val t = jobs.firstOrNull { it.jobType == "transcribe" }?.status val t = jobs.firstOrNull { it.jobType == "transcribe" }?.status
@ -702,9 +717,9 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
it.jobType == "transcribe" && it.status == "failed" it.jobType == "transcribe" && it.status == "failed"
} }
if (transcribeFailed) return false if (transcribeFailed) return false
val transcript = runCatching { parseTranscript(provider.fetchTranscript(ref.key)) } val transcript = runCatching { parseTranscript(provider.fetchTranscript(refKey)) }
.getOrNull() ?: return false .getOrNull() ?: return false
val summary = runCatching { parseSummary(provider.fetchSummary(ref.key)) }.getOrNull() val summary = runCatching { parseSummary(provider.fetchSummary(refKey)) }.getOrNull()
saveReport(DetailUi(file = f, transcript = transcript, summary = summary)) saveReport(DetailUi(file = f, transcript = transcript, summary = summary))
true true
} catch (e: Exception) { } catch (e: Exception) {
@ -1377,6 +1392,17 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
fun transcribe() { fun transcribe() {
val d = _detail.value ?: return val d = _detail.value ?: return
pollJob?.cancel() pollJob?.cancel()
// The pump (or a detail-run from elsewhere) already owns this
// file: never start a second pipeline for it. The upload path
// below creates a NEW server recording, and the mapping sidecar
// only exists once an upload completes — so mid-flight this is
// the only reliable dedup. Show the live row state instead.
if (d.file.name in inFlight || isRunning(d.file.name)) {
d.busy = _liveProgress.value[d.file.name]?.label ?: "Already queued…"
d.error = null
_detail.value = d.copy()
return
}
// A file with a known server recording re-runs the pipeline IN // A file with a known server recording re-runs the pipeline IN
// PLACE (the endpoint takes the model override too) — re-uploading // PLACE (the endpoint takes the model override too) — re-uploading
// would duplicate the recording server-side. Only never-uploaded // would duplicate the recording server-side. Only never-uploaded