This commit is contained in:
Linrador 2026-06-12 09:18:32 +02:00
parent e211ad34ab
commit 10162064ff
4 changed files with 59 additions and 57 deletions

View File

@ -203,15 +203,15 @@ func clothingSeverityWeight(label string) float64 {
switch label { switch label {
case "lingerie": case "lingerie":
return 0.64 return 0.50
case "panties", "bra": case "panties", "bra":
return 0.58 return 0.44
case "bikini": case "bikini":
return 0.42 return 0.30
case "stockings", "heels": case "stockings", "heels":
return 0.40 return 0.28
case "skirt", "dress", "hotpants", "croptop": case "skirt", "dress", "hotpants", "croptop":
return 0.34 return 0.22
default: default:
return 0.00 return 0.00
} }
@ -431,20 +431,21 @@ func contextualSegmentSeverityWeight(label string) float64 {
var score float64 var score float64
if set.HasPosition { if set.HasPosition {
// Priorität: Position > Kleidung > Objekte (Kombination erhöht den Score).
score = score =
0.66*set.Position + 0.66*set.Position +
0.17*set.Body + 0.15*set.Body +
0.10*set.Object + 0.12*set.Clothing +
0.05*set.Clothing + 0.05*set.Object +
0.02*set.Person 0.02*set.Person
if set.HasBody { if set.HasBody {
score += 0.055 score += 0.055
} }
if set.HasObject {
score += 0.040
}
if set.HasClothing { if set.HasClothing {
score += 0.030
}
if set.HasObject {
score += 0.020 score += 0.020
} }
if set.HasPerson { if set.HasPerson {
@ -461,29 +462,27 @@ func contextualSegmentSeverityWeight(label string) float64 {
score = score =
0.54*set.Body + 0.54*set.Body +
0.30*set.Object + 0.28*set.Clothing +
0.14*set.Clothing + 0.16*set.Object +
0.02*set.Person 0.02*set.Person
if set.HasBody && set.HasObject {
score += 0.09
}
if set.HasBody && set.HasClothing { if set.HasBody && set.HasClothing {
score += 0.05
}
if set.HasBody && set.HasObject {
score += 0.04 score += 0.04
} }
if set.HasObject && set.HasClothing { if set.HasClothing && set.HasObject {
score += 0.03 score += 0.03
} }
if set.HasPerson && (set.HasBody || set.HasObject || set.HasClothing) { if set.HasPerson && (set.HasBody || set.HasObject || set.HasClothing) {
score += 0.015 score += 0.015
} }
// Kleidung alleine soll interessant sein können, aber nicht stark.
if set.HasClothing && !set.HasBody && !set.HasObject { if set.HasClothing && !set.HasBody && !set.HasObject {
score = math.Min(score, 0.38) score = math.Min(score, 0.38)
} }
// Ohne Position nicht zu aggressiv.
score = math.Min(score, 0.72) score = math.Min(score, 0.72)
return ratingClamp01(score) return ratingClamp01(score)
@ -524,18 +523,18 @@ func contextualSegmentSeverityWeightFromSet(set ratingSignalSet) float64 {
if set.HasPosition { if set.HasPosition {
score = score =
0.66*set.Position + 0.66*set.Position +
0.17*set.Body + 0.15*set.Body +
0.10*set.Object + 0.12*set.Clothing +
0.05*set.Clothing + 0.05*set.Object +
0.02*set.Person 0.02*set.Person
if set.HasBody { if set.HasBody {
score += 0.055 score += 0.055
} }
if set.HasObject {
score += 0.040
}
if set.HasClothing { if set.HasClothing {
score += 0.030
}
if set.HasObject {
score += 0.020 score += 0.020
} }
if set.HasPerson { if set.HasPerson {
@ -551,17 +550,17 @@ func contextualSegmentSeverityWeightFromSet(set ratingSignalSet) float64 {
score = score =
0.54*set.Body + 0.54*set.Body +
0.30*set.Object + 0.28*set.Clothing +
0.14*set.Clothing + 0.16*set.Object +
0.02*set.Person 0.02*set.Person
if set.HasBody && set.HasObject {
score += 0.09
}
if set.HasBody && set.HasClothing { if set.HasBody && set.HasClothing {
score += 0.05
}
if set.HasBody && set.HasObject {
score += 0.04 score += 0.04
} }
if set.HasObject && set.HasClothing { if set.HasClothing && set.HasObject {
score += 0.03 score += 0.03
} }
if set.HasPerson && (set.HasBody || set.HasObject || set.HasClothing) { if set.HasPerson && (set.HasBody || set.HasObject || set.HasClothing) {
@ -1349,7 +1348,6 @@ func computeHighlightRatingWithUsername(segments []aiSegmentMeta, durationSec fl
var totalWeighted float64 var totalWeighted float64
var positionEffectiveWeighted float64 var positionEffectiveWeighted float64
var contextEffectiveWeighted float64
var peakQuality float64 var peakQuality float64
var longest float64 var longest float64
@ -1391,11 +1389,12 @@ func computeHighlightRatingWithUsername(segments []aiSegmentMeta, durationSec fl
totalWeighted += weightedDur totalWeighted += weightedDur
set := ratingSignalSetFromLabel(s.Label) set := ratingSignalSetFromLabel(s.Label)
if set.HasPosition { if !set.HasPosition {
positionEffectiveWeighted += effectiveWeightedDur // Nur Positions-Segmente fließen ins Rating ein.
} else { // Kleidung und Objekte wirken über Combo-Segmente (position+clothing etc.).
contextEffectiveWeighted += effectiveWeightedDur continue
} }
positionEffectiveWeighted += effectiveWeightedDur
if quality > peakQuality { if quality > peakQuality {
peakQuality = quality peakQuality = quality
@ -1420,29 +1419,22 @@ func computeHighlightRatingWithUsername(segments []aiSegmentMeta, durationSec fl
avgConfidence := confSum / float64(n) avgConfidence := confSum / float64(n)
positionDensity := positionEffectiveWeighted / videoMinutes positionDensity := positionEffectiveWeighted / videoMinutes
contextDensity := contextEffectiveWeighted / videoMinutes
peakNorm := ratingSmoothStep(peakQuality) peakNorm := ratingSmoothStep(peakQuality)
positionDensityNorm := ratingSoftCap(positionDensity, 5.5) positionDensityNorm := ratingSoftCap(positionDensity, 5.5)
contextDensityNorm := ratingSoftCap(contextDensity, 8.5)
coverageNorm := ratingSoftCap(weightedCoverageRatio, 0.20) coverageNorm := ratingSoftCap(weightedCoverageRatio, 0.20)
frequencyNorm := ratingSoftCap(segmentsPerMinute, 1.25)
longestNorm := ratingSoftCap(longest, 24.0) longestNorm := ratingSoftCap(longest, 24.0)
confNorm := ratingSmoothStep((avgConfidence - 0.30) / 0.65) confNorm := ratingSmoothStep((avgConfidence - 0.30) / 0.65)
// Positionen dominieren. Kleidung/Objekte fließen durch Combo-Segment-Qualität (peakNorm) ein.
// Keine Penalties, keine Caps die Formel bewertet natürlich nach Positions-Intensität.
// Summe = 1.00.
raw := raw :=
0.32*peakNorm + 0.42*positionDensityNorm +
0.25*positionDensityNorm + 0.26*peakNorm +
0.17*contextDensityNorm + 0.18*coverageNorm +
0.12*coverageNorm + 0.08*longestNorm +
0.06*longestNorm + 0.06*confNorm
0.04*frequencyNorm +
0.04*confNorm
// Ohne Position darf es trotzdem gut werden, aber nicht automatisch 5 Sterne.
if positionEffectiveWeighted <= 0 {
raw = math.Min(raw, 0.76)
}
// Sehr wenig Material nicht überbewerten. // Sehr wenig Material nicht überbewerten.
if totalFlagged < 5.0 && n <= 1 { if totalFlagged < 5.0 && n <= 1 {
@ -1477,15 +1469,14 @@ func computeHighlightRatingWithUsername(segments []aiSegmentMeta, durationSec fl
r.AvgConfidence = ratingRound(avgConfidence, 3) r.AvgConfidence = ratingRound(avgConfidence, 3)
appLogf( appLogf(
"✅ %s rating result score=%.1f stars=%d bonus=%.1f segments=%d flagged=%.2f weighted=%.2f coverage=%.4f weightedCoverage=%.4f longest=%.2f avgConf=%.3f", "✅ %s rating score=%.1f stars=%d bonus=%.1f segs=%d flagged=%.1f posDensity=%.2f coverage=%.4f longest=%.1f avgConf=%.3f",
ratingLogSubject(username), ratingLogSubject(username),
r.Score, r.Score,
r.Stars, r.Stars,
ratingRound(excellenceBonus*100, 1), ratingRound(excellenceBonus*100, 1),
r.Segments, r.Segments,
r.FlaggedSeconds, r.FlaggedSeconds,
r.WeightedFlaggedSeconds, positionDensity,
r.CoverageRatio,
r.WeightedCoverageRatio, r.WeightedCoverageRatio,
r.LongestSegmentSeconds, r.LongestSegmentSeconds,
r.AvgConfidence, r.AvgConfidence,

View File

@ -870,7 +870,7 @@ func main() {
appLogln("🔐 TLS Cert:", tlsCertFile()) appLogln("🔐 TLS Cert:", tlsCertFile())
appLogln("🔐 TLS Key: ", tlsKeyFile()) appLogln("🔐 TLS Key: ", tlsKeyFile())
} else { } else {
appLogln("🌐 HTTP-API aktiv: http://localhost:9999") appLogln("🌐 HTTP-API aktiv: https://l14pbbk95100006.tegdssd.de:9999")
} }
handler := withCORS(mux) handler := withCORS(mux)

View File

@ -108,7 +108,7 @@ func runTray(onQuit func(), statsFn func() TrayStats) {
updateStatus() updateStatus()
case <-mOpenFrontend.ClickedCh: case <-mOpenFrontend.ClickedCh:
_ = openBrowser("https://localhost:9999") _ = openBrowser("https://l14pbbk95100006.tegdssd.de:9999")
case <-mOpenRecordDir.ClickedCh: case <-mOpenRecordDir.ClickedCh:
_ = openFolder(resolveConfiguredDir(getSettings().RecordDir)) _ = openFolder(resolveConfiguredDir(getSettings().RecordDir))

View File

@ -955,8 +955,19 @@ function segmentVisualKindFromText(value: unknown): SegmentVisualKind {
function segmentVisualKind(seg: Segment): SegmentVisualKind { function segmentVisualKind(seg: Segment): SegmentVisualKind {
const rawLabel = String(seg.label || '').trim() const rawLabel = String(seg.label || '').trim()
const prettyLabel = getSegmentLabelText(rawLabel)
// Combo-Labels werden in Backend-Prioritätsreihenfolge gebaut (position > body > object > clothing).
// Jeden Teil einzeln prüfen und das erste Ergebnis zurückgeben — so verhält sich auch RatingOverlay.
if (rawLabel.toLowerCase().startsWith('combo:')) {
const parts = rawLabel.slice(6).split('+')
for (const part of parts) {
const kind = segmentVisualKindFromText(part.trim())
if (kind !== 'default') return kind
}
return 'default'
}
const prettyLabel = getSegmentLabelText(rawLabel)
const values = [rawLabel, prettyLabel] const values = [rawLabel, prettyLabel]
for (const value of values) { for (const value of values) {