Desktop: adopt server recording by title for pre-mapping files; refresh stale reports missing a summary
This commit is contained in:
parent
e3c4c06d23
commit
0fa558b1a7
1 changed files with 52 additions and 3 deletions
|
|
@ -718,10 +718,33 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
|
||||||
)
|
)
|
||||||
_detail.value = d
|
_detail.value = d
|
||||||
go(Screen.DETAIL)
|
go(Screen.DETAIL)
|
||||||
|
pollJob = scope.launch {
|
||||||
|
// Files that predate remote-id mapping have no sidecar: adopt
|
||||||
|
// the server recording by exact title match so Re-summarize
|
||||||
|
// appears and finished AI outputs become reachable.
|
||||||
|
var remoteId = d.remoteId
|
||||||
|
if (remoteId == null) {
|
||||||
|
remoteId = adoptServerRecording(d)
|
||||||
|
if (_detail.value?.file != file) return@launch
|
||||||
|
}
|
||||||
|
if (remoteId == null) return@launch
|
||||||
|
// Report written before a summary existed (or lost a race):
|
||||||
|
// pull finished outputs so the detail view isn't stale.
|
||||||
|
val report = d.reportText
|
||||||
|
if (d.transcript == null && !report.isNullOrBlank() && !report.contains("## Summary")) {
|
||||||
|
val t = runCatching { parseTranscript(provider.fetchTranscript(remoteId)) }
|
||||||
|
.getOrNull()
|
||||||
|
val s = runCatching { parseSummary(provider.fetchSummary(remoteId)) }
|
||||||
|
.getOrNull()
|
||||||
|
if (s != null) {
|
||||||
|
d.transcript = t ?: d.transcript
|
||||||
|
d.summary = s
|
||||||
|
saveReport(d)
|
||||||
|
if (_detail.value?.file == file) _detail.value = d.copy()
|
||||||
|
}
|
||||||
|
}
|
||||||
// If the file is mid-pipeline (pump running, or reprocess started
|
// If the file is mid-pipeline (pump running, or reprocess started
|
||||||
// elsewhere), show live stage/progress instead of a stale report.
|
// elsewhere), show live stage/progress instead of a stale report.
|
||||||
val remoteId = d.remoteId ?: return
|
|
||||||
pollJob = scope.launch {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
val jobs = runCatching { parseJobs(provider.fetchJobs(remoteId)) }
|
val jobs = runCatching { parseJobs(provider.fetchJobs(remoteId)) }
|
||||||
.getOrNull().orEmpty()
|
.getOrNull().orEmpty()
|
||||||
|
|
@ -736,6 +759,32 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Find the server recording matching [d]'s file by title and persist
|
||||||
|
* the mapping. Returns the recording id, or null when no server-side
|
||||||
|
* row carries this exact title. */
|
||||||
|
private suspend fun adoptServerRecording(d: DetailUi): String? {
|
||||||
|
val wanted = d.file.nameWithoutExtension
|
||||||
|
return runCatching {
|
||||||
|
var cursor: String? = null
|
||||||
|
var adopted: String? = null
|
||||||
|
var scanned = 0
|
||||||
|
do {
|
||||||
|
val page = provider.list(cursor)
|
||||||
|
val matches = page.items.filter { it.title == wanted }
|
||||||
|
// Only adopt when the title is unambiguous server-side.
|
||||||
|
if (matches.size == 1) adopted = matches.first().ref.key
|
||||||
|
if (matches.size > 1) return@runCatching null
|
||||||
|
cursor = page.nextCursor
|
||||||
|
scanned += page.items.size
|
||||||
|
} while (cursor != null && scanned < 400)
|
||||||
|
adopted?.let {
|
||||||
|
saveMapping(d.file, RemoteMapping(it, title = wanted))
|
||||||
|
d.remoteId = it
|
||||||
|
}
|
||||||
|
adopted
|
||||||
|
}.getOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
fun setOverride(model: String?) {
|
fun setOverride(model: String?) {
|
||||||
_detail.value?.let { it.overrideModel = model; _detail.value = it.copy() }
|
_detail.value?.let { it.overrideModel = model; _detail.value = it.copy() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue