bugfixes
This commit is contained in:
parent
1a559fe76d
commit
7df52ba9ef
@ -2462,6 +2462,7 @@ type analyzeLabelSegmentPoint struct {
|
|||||||
Label string
|
Label string
|
||||||
Start float64
|
Start float64
|
||||||
End float64
|
End float64
|
||||||
|
Time float64
|
||||||
Score float64
|
Score float64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2550,10 +2551,19 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
score = 1
|
score = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markerTime := hit.Time
|
||||||
|
if markerTime < 0 {
|
||||||
|
markerTime = (start + end) / 2
|
||||||
|
}
|
||||||
|
if duration > 0 {
|
||||||
|
markerTime = math.Max(0, math.Min(markerTime, duration))
|
||||||
|
}
|
||||||
|
|
||||||
byLabel[key] = append(byLabel[key], analyzeLabelSegmentPoint{
|
byLabel[key] = append(byLabel[key], analyzeLabelSegmentPoint{
|
||||||
Label: label,
|
Label: label,
|
||||||
Start: start,
|
Start: start,
|
||||||
End: end,
|
End: end,
|
||||||
|
Time: markerTime,
|
||||||
Score: score,
|
Score: score,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2580,6 +2590,8 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
curEndMarker := points[0].End
|
curEndMarker := points[0].End
|
||||||
curScoreSum := points[0].Score
|
curScoreSum := points[0].Score
|
||||||
curScoreCount := 1
|
curScoreCount := 1
|
||||||
|
curMarkerTime := points[0].Time
|
||||||
|
curBestScore := points[0].Score
|
||||||
|
|
||||||
for i := 1; i < len(points); i++ {
|
for i := 1; i < len(points); i++ {
|
||||||
n := points[i]
|
n := points[i]
|
||||||
@ -2598,6 +2610,10 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
|
|
||||||
curScoreSum += n.Score
|
curScoreSum += n.Score
|
||||||
curScoreCount++
|
curScoreCount++
|
||||||
|
if n.Score > curBestScore {
|
||||||
|
curBestScore = n.Score
|
||||||
|
curMarkerTime = n.Time
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2605,6 +2621,7 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
curLabel,
|
curLabel,
|
||||||
curStartMarker,
|
curStartMarker,
|
||||||
curEndMarker,
|
curEndMarker,
|
||||||
|
curMarkerTime,
|
||||||
curScoreSum,
|
curScoreSum,
|
||||||
curScoreCount,
|
curScoreCount,
|
||||||
halfSample,
|
halfSample,
|
||||||
@ -2620,12 +2637,15 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
curEndMarker = n.End
|
curEndMarker = n.End
|
||||||
curScoreSum = n.Score
|
curScoreSum = n.Score
|
||||||
curScoreCount = 1
|
curScoreCount = 1
|
||||||
|
curMarkerTime = n.Time
|
||||||
|
curBestScore = n.Score
|
||||||
}
|
}
|
||||||
|
|
||||||
segment := makeLabelContinuitySegment(
|
segment := makeLabelContinuitySegment(
|
||||||
curLabel,
|
curLabel,
|
||||||
curStartMarker,
|
curStartMarker,
|
||||||
curEndMarker,
|
curEndMarker,
|
||||||
|
curMarkerTime,
|
||||||
curScoreSum,
|
curScoreSum,
|
||||||
curScoreCount,
|
curScoreCount,
|
||||||
halfSample,
|
halfSample,
|
||||||
@ -2654,6 +2674,7 @@ func makeLabelContinuitySegment(
|
|||||||
label string,
|
label string,
|
||||||
startMarker float64,
|
startMarker float64,
|
||||||
endMarker float64,
|
endMarker float64,
|
||||||
|
markerTime float64,
|
||||||
scoreSum float64,
|
scoreSum float64,
|
||||||
scoreCount int,
|
scoreCount int,
|
||||||
halfSample float64,
|
halfSample float64,
|
||||||
@ -2680,6 +2701,13 @@ func makeLabelContinuitySegment(
|
|||||||
score = scoreSum / float64(scoreCount)
|
score = scoreSum / float64(scoreCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if markerTime < 0 {
|
||||||
|
markerTime = (start + end) / 2
|
||||||
|
}
|
||||||
|
if duration > 0 {
|
||||||
|
markerTime = math.Max(0, math.Min(markerTime, duration))
|
||||||
|
}
|
||||||
|
|
||||||
return aiSegmentMeta{
|
return aiSegmentMeta{
|
||||||
Label: label,
|
Label: label,
|
||||||
StartSeconds: start,
|
StartSeconds: start,
|
||||||
@ -2689,6 +2717,8 @@ func makeLabelContinuitySegment(
|
|||||||
AutoSelected: true,
|
AutoSelected: true,
|
||||||
Position: segmentPositionFromAnalyzeLabel(label),
|
Position: segmentPositionFromAnalyzeLabel(label),
|
||||||
Tags: segmentTagsFromAnalyzeLabel(label),
|
Tags: segmentTagsFromAnalyzeLabel(label),
|
||||||
|
MarkerSeconds: markerTime,
|
||||||
|
PreviewSeconds: markerTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -104,6 +104,8 @@ type aiSegmentMeta struct {
|
|||||||
AutoSelected bool `json:"autoSelected,omitempty"`
|
AutoSelected bool `json:"autoSelected,omitempty"`
|
||||||
Position string `json:"position,omitempty"`
|
Position string `json:"position,omitempty"`
|
||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
MarkerSeconds float64 `json:"markerSeconds,omitempty"`
|
||||||
|
PreviewSeconds float64 `json:"previewSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type aiAnalysisMeta struct {
|
type aiAnalysisMeta struct {
|
||||||
|
|||||||
@ -23,11 +23,11 @@ type aiRatingMeta struct {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Normales Zusammenziehen sehr kurzer Pausen.
|
// Normales Zusammenziehen sehr kurzer Pausen.
|
||||||
ratingMaxSilentGapSec = 6.5
|
ratingMaxSilentGapSec = 4.5
|
||||||
|
|
||||||
// Größere Lücken dürfen überbrückt werden,
|
// Größere Lücken dürfen überbrückt werden,
|
||||||
// wenn beide Seiten stark genug / thematisch ähnlich sind.
|
// wenn beide Seiten stark genug / thematisch ähnlich sind.
|
||||||
ratingBridgeStrongGapSec = 35.0
|
ratingBridgeStrongGapSec = 12.0
|
||||||
|
|
||||||
ratingMinSegmentDurationSec = 2.5
|
ratingMinSegmentDurationSec = 2.5
|
||||||
)
|
)
|
||||||
@ -743,7 +743,41 @@ func ratingBridgeStrengthFromSet(set ratingSignalSet) float64 {
|
|||||||
return strength
|
return strength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ratingPositionSetFromLabels(labels map[string]bool) map[string]bool {
|
||||||
|
out := map[string]bool{}
|
||||||
|
|
||||||
|
for label := range labels {
|
||||||
|
normalized := normalizeRatingSignalLabel(label)
|
||||||
|
if strings.HasPrefix(normalized, "position:") {
|
||||||
|
out[normalized] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ratingPositionSetsConflict(a map[string]bool, b map[string]bool) bool {
|
||||||
|
ap := ratingPositionSetFromLabels(a)
|
||||||
|
bp := ratingPositionSetFromLabels(b)
|
||||||
|
|
||||||
|
if len(ap) == 0 || len(bp) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for label := range ap {
|
||||||
|
if bp[label] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func ratingLabelsBridgeCompatible(a map[string]bool, b map[string]bool) bool {
|
func ratingLabelsBridgeCompatible(a map[string]bool, b map[string]bool) bool {
|
||||||
|
if ratingPositionSetsConflict(a, b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for la := range a {
|
for la := range a {
|
||||||
na := normalizeRatingSignalLabel(la)
|
na := normalizeRatingSignalLabel(la)
|
||||||
if na == "" {
|
if na == "" {
|
||||||
@ -765,9 +799,11 @@ func ratingLabelsBridgeCompatible(a map[string]bool, b map[string]bool) bool {
|
|||||||
as := ratingSignalSetFromLabels(a)
|
as := ratingSignalSetFromLabels(a)
|
||||||
bs := ratingSignalSetFromLabels(b)
|
bs := ratingSignalSetFromLabels(b)
|
||||||
|
|
||||||
if as.HasPosition && bs.HasPosition {
|
// Wichtig:
|
||||||
return true
|
// Unterschiedliche Positionen NICHT pauschal verbinden.
|
||||||
}
|
// Vorher hat "Doggy" + "Reverse Cowgirl" als kompatibel gegolten,
|
||||||
|
// nur weil beide irgendeine Position waren.
|
||||||
|
|
||||||
if as.HasBody && bs.HasBody {
|
if as.HasBody && bs.HasBody {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -840,11 +876,99 @@ func mergeRatingActivitySegments(
|
|||||||
})
|
})
|
||||||
|
|
||||||
type activityBlock struct {
|
type activityBlock struct {
|
||||||
start float64
|
start float64
|
||||||
end float64
|
end float64
|
||||||
scoreSum float64
|
scoreSum float64
|
||||||
scoreWeight float64
|
scoreWeight float64
|
||||||
labels map[string]bool
|
labels map[string]bool
|
||||||
|
positionWeights map[string]float64
|
||||||
|
marker float64
|
||||||
|
markerWeight float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var addRatingPositionWeight func(weights map[string]float64, label string, weight float64)
|
||||||
|
|
||||||
|
addRatingPositionWeight = func(weights map[string]float64, label string, weight float64) {
|
||||||
|
label = strings.ToLower(strings.TrimSpace(label))
|
||||||
|
if label == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(label, "combo:") {
|
||||||
|
raw := strings.TrimPrefix(label, "combo:")
|
||||||
|
for _, part := range strings.Split(raw, "+") {
|
||||||
|
addRatingPositionWeight(weights, part, weight)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
normalized := normalizeRatingSignalLabel(label)
|
||||||
|
if strings.HasPrefix(normalized, "position:") {
|
||||||
|
weights[normalized] += weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
effectiveRatingLabelsForBlock := func(labels map[string]bool, positionWeights map[string]float64) map[string]bool {
|
||||||
|
out := map[string]bool{}
|
||||||
|
|
||||||
|
bestPosition := ""
|
||||||
|
bestWeight := -1.0
|
||||||
|
|
||||||
|
for label := range labels {
|
||||||
|
normalized := normalizeRatingSignalLabel(label)
|
||||||
|
if normalized == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(normalized, "position:") {
|
||||||
|
w := positionWeights[normalized]
|
||||||
|
if w <= 0 {
|
||||||
|
w = ratingSegmentSeverity(normalized)
|
||||||
|
}
|
||||||
|
|
||||||
|
if w > bestWeight {
|
||||||
|
bestWeight = w
|
||||||
|
bestPosition = normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
out[normalized] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if bestPosition != "" {
|
||||||
|
out[bestPosition] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentMarker := func(s aiSegmentMeta) float64 {
|
||||||
|
if s.PreviewSeconds > 0 {
|
||||||
|
return s.PreviewSeconds
|
||||||
|
}
|
||||||
|
if s.MarkerSeconds > 0 {
|
||||||
|
return s.MarkerSeconds
|
||||||
|
}
|
||||||
|
if s.EndSeconds > s.StartSeconds {
|
||||||
|
return (s.StartSeconds + s.EndSeconds) / 2
|
||||||
|
}
|
||||||
|
return s.StartSeconds
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentMarkerWeight := func(s aiSegmentMeta) float64 {
|
||||||
|
conf := ratingClamp01(s.Score)
|
||||||
|
if conf <= 0 {
|
||||||
|
conf = 0.50
|
||||||
|
}
|
||||||
|
|
||||||
|
sev := ratingSegmentSeverity(s.Label)
|
||||||
|
if sev <= 0 {
|
||||||
|
sev = 0.50
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf * sev
|
||||||
}
|
}
|
||||||
|
|
||||||
newBlock := func(s aiSegmentMeta) activityBlock {
|
newBlock := func(s aiSegmentMeta) activityBlock {
|
||||||
@ -857,12 +981,21 @@ func mergeRatingActivitySegments(
|
|||||||
conf = 0.50
|
conf = 0.50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
positionWeights := map[string]float64{}
|
||||||
|
addRatingPositionWeight(positionWeights, s.Label, conf*math.Max(1, dur))
|
||||||
|
|
||||||
|
marker := segmentMarker(s)
|
||||||
|
markerWeight := segmentMarkerWeight(s)
|
||||||
|
|
||||||
return activityBlock{
|
return activityBlock{
|
||||||
start: s.StartSeconds,
|
start: s.StartSeconds,
|
||||||
end: s.EndSeconds,
|
end: s.EndSeconds,
|
||||||
scoreSum: conf * dur,
|
scoreSum: conf * dur,
|
||||||
scoreWeight: dur,
|
scoreWeight: dur,
|
||||||
labels: labels,
|
labels: labels,
|
||||||
|
positionWeights: positionWeights,
|
||||||
|
marker: marker,
|
||||||
|
markerWeight: markerWeight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +1005,8 @@ func mergeRatingActivitySegments(
|
|||||||
return aiSegmentMeta{}, false
|
return aiSegmentMeta{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
label := buildRatingComboLabel(b.labels)
|
effectiveLabels := effectiveRatingLabelsForBlock(b.labels, b.positionWeights)
|
||||||
|
label := buildRatingComboLabel(effectiveLabels)
|
||||||
if label == "" {
|
if label == "" {
|
||||||
return aiSegmentMeta{}, false
|
return aiSegmentMeta{}, false
|
||||||
}
|
}
|
||||||
@ -901,6 +1035,8 @@ func mergeRatingActivitySegments(
|
|||||||
AutoSelected: true,
|
AutoSelected: true,
|
||||||
Position: segmentPositionFromAnalyzeLabel(label),
|
Position: segmentPositionFromAnalyzeLabel(label),
|
||||||
Tags: segmentTagsFromAnalyzeLabel(label),
|
Tags: segmentTagsFromAnalyzeLabel(label),
|
||||||
|
MarkerSeconds: b.marker,
|
||||||
|
PreviewSeconds: b.marker,
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,8 +1092,17 @@ func mergeRatingActivitySegments(
|
|||||||
if conf <= 0 {
|
if conf <= 0 {
|
||||||
conf = 0.50
|
conf = 0.50
|
||||||
}
|
}
|
||||||
|
|
||||||
cur.scoreSum += conf * dur
|
cur.scoreSum += conf * dur
|
||||||
cur.scoreWeight += dur
|
cur.scoreWeight += dur
|
||||||
|
|
||||||
|
addRatingPositionWeight(cur.positionWeights, n.Label, conf*math.Max(1, dur))
|
||||||
|
}
|
||||||
|
|
||||||
|
nextMarkerWeight := segmentMarkerWeight(n)
|
||||||
|
if nextMarkerWeight > cur.markerWeight {
|
||||||
|
cur.markerWeight = nextMarkerWeight
|
||||||
|
cur.marker = segmentMarker(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
addRatingLabelsFromSegment(cur.labels, n.Label)
|
addRatingLabelsFromSegment(cur.labels, n.Label)
|
||||||
|
|||||||
@ -888,22 +888,13 @@ function segmentAnchorTime(
|
|||||||
obj: Record<string, unknown>,
|
obj: Record<string, unknown>,
|
||||||
durationSeconds: number
|
durationSeconds: number
|
||||||
): number | undefined {
|
): number | undefined {
|
||||||
const start = firstSegmentTimeNumber(obj, [
|
|
||||||
'startSec',
|
|
||||||
'startSeconds',
|
|
||||||
'start_s',
|
|
||||||
'start',
|
|
||||||
'from',
|
|
||||||
'startMs',
|
|
||||||
'startRatio',
|
|
||||||
'startPercent',
|
|
||||||
'startPct',
|
|
||||||
], durationSeconds)
|
|
||||||
|
|
||||||
const marker = firstSegmentTimeNumber(obj, [
|
const marker = firstSegmentTimeNumber(obj, [
|
||||||
'markerTime',
|
'previewSeconds',
|
||||||
'markerSec',
|
'previewSec',
|
||||||
|
'previewTime',
|
||||||
'markerSeconds',
|
'markerSeconds',
|
||||||
|
'markerSec',
|
||||||
|
'markerTime',
|
||||||
'time',
|
'time',
|
||||||
't',
|
't',
|
||||||
'timestamp',
|
'timestamp',
|
||||||
@ -918,18 +909,41 @@ function segmentAnchorTime(
|
|||||||
'timestampPct',
|
'timestampPct',
|
||||||
], durationSeconds)
|
], durationSeconds)
|
||||||
|
|
||||||
if (typeof start === 'number') return start
|
|
||||||
if (typeof marker === 'number') return marker
|
if (typeof marker === 'number') return marker
|
||||||
|
|
||||||
return undefined
|
const start = firstSegmentTimeNumber(obj, [
|
||||||
|
'startSec',
|
||||||
|
'startSeconds',
|
||||||
|
'start_s',
|
||||||
|
'start',
|
||||||
|
'from',
|
||||||
|
'startMs',
|
||||||
|
'startRatio',
|
||||||
|
'startPercent',
|
||||||
|
'startPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
|
return typeof start === 'number' ? start : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentPreviewTime(
|
function segmentPreviewTime(
|
||||||
obj: Record<string, unknown>,
|
obj: Record<string, unknown>,
|
||||||
durationSeconds: number
|
durationSeconds: number
|
||||||
): number | undefined {
|
): number | undefined {
|
||||||
const anchor = segmentAnchorTime(obj, durationSeconds)
|
const marker = segmentAnchorTime(obj, durationSeconds)
|
||||||
if (typeof anchor === 'number') return anchor
|
if (typeof marker === 'number') return marker
|
||||||
|
|
||||||
|
const start = firstSegmentTimeNumber(obj, [
|
||||||
|
'startSec',
|
||||||
|
'startSeconds',
|
||||||
|
'start_s',
|
||||||
|
'start',
|
||||||
|
'from',
|
||||||
|
'startMs',
|
||||||
|
'startRatio',
|
||||||
|
'startPercent',
|
||||||
|
'startPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
const end = firstSegmentTimeNumber(obj, [
|
const end = firstSegmentTimeNumber(obj, [
|
||||||
'endSec',
|
'endSec',
|
||||||
@ -943,7 +957,14 @@ function segmentPreviewTime(
|
|||||||
'endPct',
|
'endPct',
|
||||||
], durationSeconds)
|
], durationSeconds)
|
||||||
|
|
||||||
return typeof end === 'number' ? end : undefined
|
if (typeof start === 'number' && typeof end === 'number') {
|
||||||
|
return Math.max(0, (start + end) / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof start === 'number') return start
|
||||||
|
if (typeof end === 'number') return end
|
||||||
|
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentOpenTime(
|
function segmentOpenTime(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user