bugfixes
This commit is contained in:
parent
06b4ff2666
commit
fd0bab67fb
@ -1,2 +1,2 @@
|
||||
HTTPS_ENABLED=1
|
||||
HTTPS_ENABLED=0
|
||||
AUTH_RP_ORIGINS=https://l14pbbk95100006.tegdssd.de:9999,https://l14pbbk95100006.tegdssd.de:5173,https://localhost:9999,https://127.0.0.1:9999,https://10.0.1.25:9999,http://localhost:5173,http://127.0.0.1:5173,http://10.0.1.25:5173
|
||||
@ -25,7 +25,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const trainingUncertainCandidateCount = 5
|
||||
const trainingUncertainCandidateCount = 10
|
||||
|
||||
type TrainingLabels struct {
|
||||
People []string `json:"people"`
|
||||
@ -1078,7 +1078,7 @@ func trainingLabelsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
trainingWriteJSON(w, http.StatusOK, defaultTrainingLabelsFromJSON())
|
||||
}
|
||||
|
||||
const trainingImportVideoDefaultFrameCount = 8
|
||||
const trainingImportVideoDefaultFrameCount = 10
|
||||
const trainingImportVideoMaxFrameCount = 30
|
||||
|
||||
type TrainingImportVideoRequest struct {
|
||||
@ -3229,6 +3229,8 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
||||
missing = 1
|
||||
}
|
||||
|
||||
candidateWindowTotal := trainingUncertainCandidateCount
|
||||
|
||||
const stepsPerCandidate = 4
|
||||
totalSteps := missing*stepsPerCandidate + 1
|
||||
|
||||
@ -3238,7 +3240,7 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
||||
attempt := i + 1
|
||||
stepStart := i*stepsPerCandidate + 1
|
||||
|
||||
prefix := fmt.Sprintf("Kandidat %d/%d: ", attempt, missing)
|
||||
prefix := fmt.Sprintf("Kandidat %d/%d: ", attempt, candidateWindowTotal)
|
||||
|
||||
candidate, err := trainingCreateUncertainCandidateWithProgress(
|
||||
root,
|
||||
@ -3258,7 +3260,7 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
||||
stepStart+stepsPerCandidate-1,
|
||||
totalSteps,
|
||||
"",
|
||||
fmt.Sprintf("Kandidat %d/%d fehlgeschlagen…", attempt, missing),
|
||||
fmt.Sprintf("Kandidat %d/%d fehlgeschlagen…", attempt, candidateWindowTotal),
|
||||
)
|
||||
|
||||
continue
|
||||
@ -3275,7 +3277,7 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
||||
fmt.Sprintf(
|
||||
"Kandidat %d/%d bewertet · Unsicherheit %.0f%%",
|
||||
attempt,
|
||||
missing,
|
||||
candidateWindowTotal,
|
||||
candidate.score*100,
|
||||
),
|
||||
)
|
||||
|
||||
@ -703,6 +703,56 @@ function firstNumber(obj: Record<string, unknown>, keys: string[]): number | und
|
||||
return undefined
|
||||
}
|
||||
|
||||
function normalizeSegmentTimeValue(
|
||||
key: string,
|
||||
raw: unknown,
|
||||
durationSeconds: number
|
||||
): number | undefined {
|
||||
const n = Number(raw)
|
||||
if (!Number.isFinite(n) || n < 0) return undefined
|
||||
|
||||
const k = key.toLowerCase()
|
||||
const duration = Number(durationSeconds)
|
||||
const hasDuration = Number.isFinite(duration) && duration > 0
|
||||
|
||||
if (k.endsWith('ms') || k.includes('millisecond')) {
|
||||
return n / 1000
|
||||
}
|
||||
|
||||
if (hasDuration) {
|
||||
// Einige Analyse-Backends schreiben Millisekunden in generische Felder
|
||||
// wie `start`, `end`, `time` oder `timestamp`. Ohne diese Korrektur
|
||||
// würde der Player z.B. 95500 als 95.500 Sekunden statt 95,5 Sekunden suchen.
|
||||
const asMillis = n / 1000
|
||||
if (n > duration + 1 && asMillis <= duration + 1) {
|
||||
return asMillis
|
||||
}
|
||||
|
||||
// Ebenfalls unterstützen: normalisierte Positionen 0..1, falls ein
|
||||
// Backend explizit ratio/percent/pct im Feldnamen verwendet.
|
||||
if (n >= 0 && n <= 1 && /(ratio|percent|pct)$/.test(k)) {
|
||||
return n * duration
|
||||
}
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
function firstSegmentTimeNumber(
|
||||
obj: Record<string, unknown>,
|
||||
keys: string[],
|
||||
durationSeconds: number
|
||||
): number | undefined {
|
||||
for (const key of keys) {
|
||||
if (!(key in obj)) continue
|
||||
|
||||
const n = normalizeSegmentTimeValue(key, obj[key], durationSeconds)
|
||||
if (typeof n === 'number') return n
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
type PreviewSpriteMeta = {
|
||||
path: string
|
||||
count: number
|
||||
@ -832,73 +882,81 @@ function readMetaDurationSeconds(metaRaw: unknown): number {
|
||||
return Number.isFinite(n) && n > 0 ? n : 0
|
||||
}
|
||||
|
||||
function segmentPreviewTime(obj: Record<string, unknown>): number | undefined {
|
||||
const start = firstNumber(obj, [
|
||||
const RATING_SEGMENT_OPEN_PREROLL_SECONDS = 3
|
||||
|
||||
function segmentAnchorTime(
|
||||
obj: Record<string, unknown>,
|
||||
durationSeconds: number
|
||||
): number | undefined {
|
||||
const start = firstSegmentTimeNumber(obj, [
|
||||
'startSec',
|
||||
'startSeconds',
|
||||
'start_s',
|
||||
'start',
|
||||
'from',
|
||||
'startMs',
|
||||
])
|
||||
'startRatio',
|
||||
'startPercent',
|
||||
'startPct',
|
||||
], durationSeconds)
|
||||
|
||||
const end = firstNumber(obj, [
|
||||
const marker = firstSegmentTimeNumber(obj, [
|
||||
'markerTime',
|
||||
'markerSec',
|
||||
'markerSeconds',
|
||||
'time',
|
||||
't',
|
||||
'timestamp',
|
||||
'at',
|
||||
'timeMs',
|
||||
'timestampMs',
|
||||
'timeRatio',
|
||||
'timestampRatio',
|
||||
'timePercent',
|
||||
'timestampPercent',
|
||||
'timePct',
|
||||
'timestampPct',
|
||||
], durationSeconds)
|
||||
|
||||
if (typeof start === 'number') return start
|
||||
if (typeof marker === 'number') return marker
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function segmentPreviewTime(
|
||||
obj: Record<string, unknown>,
|
||||
durationSeconds: number
|
||||
): number | undefined {
|
||||
const anchor = segmentAnchorTime(obj, durationSeconds)
|
||||
if (typeof anchor === 'number') return anchor
|
||||
|
||||
const end = firstSegmentTimeNumber(obj, [
|
||||
'endSec',
|
||||
'endSeconds',
|
||||
'end_s',
|
||||
'end',
|
||||
'to',
|
||||
'endMs',
|
||||
])
|
||||
'endRatio',
|
||||
'endPercent',
|
||||
'endPct',
|
||||
], durationSeconds)
|
||||
|
||||
const marker = firstNumber(obj, [
|
||||
'markerTime',
|
||||
'markerSec',
|
||||
'markerSeconds',
|
||||
'time',
|
||||
't',
|
||||
'timestamp',
|
||||
'at',
|
||||
'timeMs',
|
||||
'timestampMs',
|
||||
])
|
||||
|
||||
if (typeof start === 'number' && typeof end === 'number' && end > start) {
|
||||
return start + (end - start) / 2
|
||||
}
|
||||
|
||||
if (typeof marker === 'number') return marker
|
||||
if (typeof start === 'number') return start
|
||||
|
||||
return undefined
|
||||
return typeof end === 'number' ? end : undefined
|
||||
}
|
||||
|
||||
function segmentOpenTime(obj: Record<string, unknown>): number | undefined {
|
||||
const start = firstNumber(obj, [
|
||||
'startSec',
|
||||
'startSeconds',
|
||||
'start_s',
|
||||
'start',
|
||||
'from',
|
||||
'startMs',
|
||||
])
|
||||
function segmentOpenTime(
|
||||
obj: Record<string, unknown>,
|
||||
durationSeconds: number
|
||||
): number | undefined {
|
||||
const anchor =
|
||||
segmentAnchorTime(obj, durationSeconds) ??
|
||||
segmentPreviewTime(obj, durationSeconds)
|
||||
|
||||
const marker = firstNumber(obj, [
|
||||
'markerTime',
|
||||
'markerSec',
|
||||
'markerSeconds',
|
||||
'time',
|
||||
't',
|
||||
'timestamp',
|
||||
'at',
|
||||
'timeMs',
|
||||
'timestampMs',
|
||||
])
|
||||
if (typeof anchor !== 'number') return undefined
|
||||
|
||||
if (typeof start === 'number') return start
|
||||
if (typeof marker === 'number') return marker
|
||||
|
||||
return segmentPreviewTime(obj)
|
||||
return Math.max(0, anchor - RATING_SEGMENT_OPEN_PREROLL_SECONDS)
|
||||
}
|
||||
|
||||
function spriteFrameIndexFromTime(
|
||||
@ -1009,8 +1067,8 @@ function segmentValueLabel(obj: Record<string, unknown>): string | undefined {
|
||||
return score.toFixed(2).replace(/\.?0+$/, '')
|
||||
}
|
||||
|
||||
function segmentTimeLabel(obj: Record<string, unknown>): string | undefined {
|
||||
const start = firstNumber(obj, [
|
||||
function segmentTimeLabel(obj: Record<string, unknown>, durationSeconds: number): string | undefined {
|
||||
const start = firstSegmentTimeNumber(obj, [
|
||||
'startSec',
|
||||
'startSeconds',
|
||||
'start_s',
|
||||
@ -1020,16 +1078,22 @@ function segmentTimeLabel(obj: Record<string, unknown>): string | undefined {
|
||||
'time',
|
||||
'timestamp',
|
||||
'startMs',
|
||||
])
|
||||
'startRatio',
|
||||
'startPercent',
|
||||
'startPct',
|
||||
], durationSeconds)
|
||||
|
||||
const end = firstNumber(obj, [
|
||||
const end = firstSegmentTimeNumber(obj, [
|
||||
'endSec',
|
||||
'endSeconds',
|
||||
'end_s',
|
||||
'end',
|
||||
'to',
|
||||
'endMs',
|
||||
])
|
||||
'endRatio',
|
||||
'endPercent',
|
||||
'endPct',
|
||||
], durationSeconds)
|
||||
|
||||
const duration = firstNumber(obj, [
|
||||
'durationSec',
|
||||
@ -1250,8 +1314,8 @@ export function readRatingSegments(metaRaw: unknown): RatingSegment[] {
|
||||
.join(', ')
|
||||
: undefined
|
||||
|
||||
const previewTime = segmentPreviewTime(raw)
|
||||
const openAtSec = segmentOpenTime(raw)
|
||||
const previewTime = segmentPreviewTime(raw, durationSeconds)
|
||||
const openAtSec = segmentOpenTime(raw, durationSeconds)
|
||||
|
||||
const preview =
|
||||
spriteMeta && typeof previewTime === 'number'
|
||||
@ -1263,7 +1327,7 @@ export function readRatingSegments(metaRaw: unknown): RatingSegment[] {
|
||||
return {
|
||||
key: String(raw.id ?? raw.key ?? `${index}`),
|
||||
title,
|
||||
timeLabel: segmentTimeLabel(raw),
|
||||
timeLabel: segmentTimeLabel(raw, durationSeconds),
|
||||
valueLabel: segmentValueLabel(raw),
|
||||
detail,
|
||||
tags: readSegmentTags(raw),
|
||||
|
||||
@ -255,7 +255,7 @@ export default function RecordJobActions({
|
||||
jobId: String((job as any)?.id ?? ''),
|
||||
output,
|
||||
sourceFile: baseName(output),
|
||||
count: 8,
|
||||
count: 10,
|
||||
}
|
||||
|
||||
// Falls TrainingTab gerade nicht gemountet ist.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// frontend/src/components/ui/TrainingTab.tsx
|
||||
// frontend\src\components\ui\TrainingTab.tsx
|
||||
'use client'
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'
|
||||
@ -2797,14 +2797,16 @@ export default function TrainingTab(props: {
|
||||
|
||||
setLoadingPreviewCandidate('')
|
||||
|
||||
const TRAINING_IMPORT_FRAME_COUNT = 10
|
||||
|
||||
const detail: PendingTrainingVideoImport = {
|
||||
jobId: String(raw?.jobId || '').trim(),
|
||||
output,
|
||||
sourceFile: String(raw?.sourceFile || '').trim(),
|
||||
count: Number(raw?.count || 8),
|
||||
count: Number(raw?.count || TRAINING_IMPORT_FRAME_COUNT),
|
||||
}
|
||||
|
||||
const importKey = `${detail.jobId || ''}|${detail.output}|${detail.count || 8}`
|
||||
const importKey = `${detail.jobId || ''}|${detail.output}|${detail.count || TRAINING_IMPORT_FRAME_COUNT}`
|
||||
|
||||
// Verhindert Doppelimport durch sessionStorage + CustomEvent.
|
||||
if (videoImportInFlightKeyRef.current === importKey) {
|
||||
@ -2838,7 +2840,7 @@ export default function TrainingTab(props: {
|
||||
body: JSON.stringify({
|
||||
jobId: detail.jobId,
|
||||
output: detail.output,
|
||||
count: detail.count || 8,
|
||||
count: detail.count || TRAINING_IMPORT_FRAME_COUNT,
|
||||
analysisRequestId: requestId,
|
||||
}),
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user