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
|
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"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const trainingUncertainCandidateCount = 5
|
const trainingUncertainCandidateCount = 10
|
||||||
|
|
||||||
type TrainingLabels struct {
|
type TrainingLabels struct {
|
||||||
People []string `json:"people"`
|
People []string `json:"people"`
|
||||||
@ -1078,7 +1078,7 @@ func trainingLabelsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
trainingWriteJSON(w, http.StatusOK, defaultTrainingLabelsFromJSON())
|
trainingWriteJSON(w, http.StatusOK, defaultTrainingLabelsFromJSON())
|
||||||
}
|
}
|
||||||
|
|
||||||
const trainingImportVideoDefaultFrameCount = 8
|
const trainingImportVideoDefaultFrameCount = 10
|
||||||
const trainingImportVideoMaxFrameCount = 30
|
const trainingImportVideoMaxFrameCount = 30
|
||||||
|
|
||||||
type TrainingImportVideoRequest struct {
|
type TrainingImportVideoRequest struct {
|
||||||
@ -3229,6 +3229,8 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
|||||||
missing = 1
|
missing = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
candidateWindowTotal := trainingUncertainCandidateCount
|
||||||
|
|
||||||
const stepsPerCandidate = 4
|
const stepsPerCandidate = 4
|
||||||
totalSteps := missing*stepsPerCandidate + 1
|
totalSteps := missing*stepsPerCandidate + 1
|
||||||
|
|
||||||
@ -3238,7 +3240,7 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
|||||||
attempt := i + 1
|
attempt := i + 1
|
||||||
stepStart := i*stepsPerCandidate + 1
|
stepStart := i*stepsPerCandidate + 1
|
||||||
|
|
||||||
prefix := fmt.Sprintf("Kandidat %d/%d: ", attempt, missing)
|
prefix := fmt.Sprintf("Kandidat %d/%d: ", attempt, candidateWindowTotal)
|
||||||
|
|
||||||
candidate, err := trainingCreateUncertainCandidateWithProgress(
|
candidate, err := trainingCreateUncertainCandidateWithProgress(
|
||||||
root,
|
root,
|
||||||
@ -3258,7 +3260,7 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
|||||||
stepStart+stepsPerCandidate-1,
|
stepStart+stepsPerCandidate-1,
|
||||||
totalSteps,
|
totalSteps,
|
||||||
"",
|
"",
|
||||||
fmt.Sprintf("Kandidat %d/%d fehlgeschlagen…", attempt, missing),
|
fmt.Sprintf("Kandidat %d/%d fehlgeschlagen…", attempt, candidateWindowTotal),
|
||||||
)
|
)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
@ -3275,7 +3277,7 @@ func trainingCreateUncertainNextSampleWithProgress(startedAtMs int64, requestID
|
|||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"Kandidat %d/%d bewertet · Unsicherheit %.0f%%",
|
"Kandidat %d/%d bewertet · Unsicherheit %.0f%%",
|
||||||
attempt,
|
attempt,
|
||||||
missing,
|
candidateWindowTotal,
|
||||||
candidate.score*100,
|
candidate.score*100,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -703,6 +703,56 @@ function firstNumber(obj: Record<string, unknown>, keys: string[]): number | und
|
|||||||
return undefined
|
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 = {
|
type PreviewSpriteMeta = {
|
||||||
path: string
|
path: string
|
||||||
count: number
|
count: number
|
||||||
@ -832,73 +882,81 @@ function readMetaDurationSeconds(metaRaw: unknown): number {
|
|||||||
return Number.isFinite(n) && n > 0 ? n : 0
|
return Number.isFinite(n) && n > 0 ? n : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentPreviewTime(obj: Record<string, unknown>): number | undefined {
|
const RATING_SEGMENT_OPEN_PREROLL_SECONDS = 3
|
||||||
const start = firstNumber(obj, [
|
|
||||||
|
function segmentAnchorTime(
|
||||||
|
obj: Record<string, unknown>,
|
||||||
|
durationSeconds: number
|
||||||
|
): number | undefined {
|
||||||
|
const start = firstSegmentTimeNumber(obj, [
|
||||||
'startSec',
|
'startSec',
|
||||||
'startSeconds',
|
'startSeconds',
|
||||||
'start_s',
|
'start_s',
|
||||||
'start',
|
'start',
|
||||||
'from',
|
'from',
|
||||||
'startMs',
|
'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',
|
'endSec',
|
||||||
'endSeconds',
|
'endSeconds',
|
||||||
'end_s',
|
'end_s',
|
||||||
'end',
|
'end',
|
||||||
'to',
|
'to',
|
||||||
'endMs',
|
'endMs',
|
||||||
])
|
'endRatio',
|
||||||
|
'endPercent',
|
||||||
|
'endPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
const marker = firstNumber(obj, [
|
return typeof end === 'number' ? end : undefined
|
||||||
'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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentOpenTime(obj: Record<string, unknown>): number | undefined {
|
function segmentOpenTime(
|
||||||
const start = firstNumber(obj, [
|
obj: Record<string, unknown>,
|
||||||
'startSec',
|
durationSeconds: number
|
||||||
'startSeconds',
|
): number | undefined {
|
||||||
'start_s',
|
const anchor =
|
||||||
'start',
|
segmentAnchorTime(obj, durationSeconds) ??
|
||||||
'from',
|
segmentPreviewTime(obj, durationSeconds)
|
||||||
'startMs',
|
|
||||||
])
|
|
||||||
|
|
||||||
const marker = firstNumber(obj, [
|
if (typeof anchor !== 'number') return undefined
|
||||||
'markerTime',
|
|
||||||
'markerSec',
|
|
||||||
'markerSeconds',
|
|
||||||
'time',
|
|
||||||
't',
|
|
||||||
'timestamp',
|
|
||||||
'at',
|
|
||||||
'timeMs',
|
|
||||||
'timestampMs',
|
|
||||||
])
|
|
||||||
|
|
||||||
if (typeof start === 'number') return start
|
return Math.max(0, anchor - RATING_SEGMENT_OPEN_PREROLL_SECONDS)
|
||||||
if (typeof marker === 'number') return marker
|
|
||||||
|
|
||||||
return segmentPreviewTime(obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function spriteFrameIndexFromTime(
|
function spriteFrameIndexFromTime(
|
||||||
@ -1009,8 +1067,8 @@ function segmentValueLabel(obj: Record<string, unknown>): string | undefined {
|
|||||||
return score.toFixed(2).replace(/\.?0+$/, '')
|
return score.toFixed(2).replace(/\.?0+$/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentTimeLabel(obj: Record<string, unknown>): string | undefined {
|
function segmentTimeLabel(obj: Record<string, unknown>, durationSeconds: number): string | undefined {
|
||||||
const start = firstNumber(obj, [
|
const start = firstSegmentTimeNumber(obj, [
|
||||||
'startSec',
|
'startSec',
|
||||||
'startSeconds',
|
'startSeconds',
|
||||||
'start_s',
|
'start_s',
|
||||||
@ -1020,16 +1078,22 @@ function segmentTimeLabel(obj: Record<string, unknown>): string | undefined {
|
|||||||
'time',
|
'time',
|
||||||
'timestamp',
|
'timestamp',
|
||||||
'startMs',
|
'startMs',
|
||||||
])
|
'startRatio',
|
||||||
|
'startPercent',
|
||||||
|
'startPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
const end = firstNumber(obj, [
|
const end = firstSegmentTimeNumber(obj, [
|
||||||
'endSec',
|
'endSec',
|
||||||
'endSeconds',
|
'endSeconds',
|
||||||
'end_s',
|
'end_s',
|
||||||
'end',
|
'end',
|
||||||
'to',
|
'to',
|
||||||
'endMs',
|
'endMs',
|
||||||
])
|
'endRatio',
|
||||||
|
'endPercent',
|
||||||
|
'endPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
const duration = firstNumber(obj, [
|
const duration = firstNumber(obj, [
|
||||||
'durationSec',
|
'durationSec',
|
||||||
@ -1250,8 +1314,8 @@ export function readRatingSegments(metaRaw: unknown): RatingSegment[] {
|
|||||||
.join(', ')
|
.join(', ')
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
const previewTime = segmentPreviewTime(raw)
|
const previewTime = segmentPreviewTime(raw, durationSeconds)
|
||||||
const openAtSec = segmentOpenTime(raw)
|
const openAtSec = segmentOpenTime(raw, durationSeconds)
|
||||||
|
|
||||||
const preview =
|
const preview =
|
||||||
spriteMeta && typeof previewTime === 'number'
|
spriteMeta && typeof previewTime === 'number'
|
||||||
@ -1263,7 +1327,7 @@ export function readRatingSegments(metaRaw: unknown): RatingSegment[] {
|
|||||||
return {
|
return {
|
||||||
key: String(raw.id ?? raw.key ?? `${index}`),
|
key: String(raw.id ?? raw.key ?? `${index}`),
|
||||||
title,
|
title,
|
||||||
timeLabel: segmentTimeLabel(raw),
|
timeLabel: segmentTimeLabel(raw, durationSeconds),
|
||||||
valueLabel: segmentValueLabel(raw),
|
valueLabel: segmentValueLabel(raw),
|
||||||
detail,
|
detail,
|
||||||
tags: readSegmentTags(raw),
|
tags: readSegmentTags(raw),
|
||||||
|
|||||||
@ -255,7 +255,7 @@ export default function RecordJobActions({
|
|||||||
jobId: String((job as any)?.id ?? ''),
|
jobId: String((job as any)?.id ?? ''),
|
||||||
output,
|
output,
|
||||||
sourceFile: baseName(output),
|
sourceFile: baseName(output),
|
||||||
count: 8,
|
count: 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Falls TrainingTab gerade nicht gemountet ist.
|
// Falls TrainingTab gerade nicht gemountet ist.
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// frontend/src/components/ui/TrainingTab.tsx
|
// frontend\src\components\ui\TrainingTab.tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'
|
||||||
@ -2797,14 +2797,16 @@ export default function TrainingTab(props: {
|
|||||||
|
|
||||||
setLoadingPreviewCandidate('')
|
setLoadingPreviewCandidate('')
|
||||||
|
|
||||||
|
const TRAINING_IMPORT_FRAME_COUNT = 10
|
||||||
|
|
||||||
const detail: PendingTrainingVideoImport = {
|
const detail: PendingTrainingVideoImport = {
|
||||||
jobId: String(raw?.jobId || '').trim(),
|
jobId: String(raw?.jobId || '').trim(),
|
||||||
output,
|
output,
|
||||||
sourceFile: String(raw?.sourceFile || '').trim(),
|
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.
|
// Verhindert Doppelimport durch sessionStorage + CustomEvent.
|
||||||
if (videoImportInFlightKeyRef.current === importKey) {
|
if (videoImportInFlightKeyRef.current === importKey) {
|
||||||
@ -2838,7 +2840,7 @@ export default function TrainingTab(props: {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
jobId: detail.jobId,
|
jobId: detail.jobId,
|
||||||
output: detail.output,
|
output: detail.output,
|
||||||
count: detail.count || 8,
|
count: detail.count || TRAINING_IMPORT_FRAME_COUNT,
|
||||||
analysisRequestId: requestId,
|
analysisRequestId: requestId,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user