Добавил поиск метаданных по каталогам

This commit is contained in:
2026-06-14 15:21:01 +03:00
parent 9c1b178e46
commit 5087f35861
21 changed files with 1435 additions and 72 deletions
+64 -7
View File
@@ -76,15 +76,72 @@ func validateSchema(p *Plan, in Input) error {
return nil
}
// decide считает решение модели уверенности. В Ф2 метабазы выключены, а без
// подтверждённого матча в базе авто-раскладка не делается (recognition.md),
// поэтому Auto всегда false; здесь же копим структурные предупреждения и
// расхождения с пред-парсом — они объясняют ревью человеку.
func decide(p Plan, pre PreParse) Decision {
reasons := []string{"матч в базе не подтверждён (метабазы отключены в Ф2) → review"}
// decide считает решение модели уверенности (см. recognition.md). Авто —
// только если выполнено всё: подтверждённый единичный матч в базе; чистая
// структурная валидация (для сериала — число серий бьётся с базой);
// согласованность с пред-парсом; самооценка LLM не ниже порога. Любая
// невыполненная — причина ухода в review.
func decide(p Plan, pre PreParse, match *Match, metadataEnabled bool, threshold float64) Decision {
var reasons []string
switch {
case !metadataEnabled:
reasons = append(reasons, "метабазы отключены → авто-раскладка недоступна")
case match == nil:
reasons = append(reasons, "не найдено в базе или несколько кандидатов")
}
reasons = append(reasons, structuralWarnings(p)...)
if match != nil && p.Type == MediaSeries {
reasons = append(reasons, episodeCountWarnings(p, match.SeasonEpisodeCounts)...)
}
reasons = append(reasons, consistencyWarnings(p, pre)...)
return Decision{Auto: false, Reasons: reasons}
if p.Confidence < threshold {
reasons = append(reasons,
fmt.Sprintf("уверенность %.2f ниже порога %.2f", p.Confidence, threshold))
}
return Decision{Auto: len(reasons) == 0, Reasons: reasons}
}
// episodeCountWarnings сверяет число распознанных серий по сезонам с базой.
// Нет данных по сезону → блокируем авто (полноту пака не подтвердить).
func episodeCountWarnings(p Plan, counts map[int]int) []string {
recognized := map[int]int{}
for _, f := range p.Files {
if f.Role == RoleEpisode && f.Episode != nil {
season := 0
if f.Season != nil {
season = *f.Season
}
recognized[season]++
}
}
var w []string
for _, season := range sortedKeys(toSlices(recognized)) {
rc := recognized[season]
dbc, ok := counts[season]
switch {
case !ok || dbc == 0:
w = append(w, fmt.Sprintf("сезон %d: в базе нет данных о числе серий", season))
case rc != dbc:
w = append(w, fmt.Sprintf("сезон %d: распознано серий %d, в базе %d", season, rc, dbc))
}
}
return w
}
// toSlices превращает map[int]int в map[int][]int для sortedKeys (нужны
// только ключи).
func toSlices(m map[int]int) map[int][]int {
out := make(map[int][]int, len(m))
for k := range m {
out[k] = nil
}
return out
}
// structuralWarnings — нарушения структуры плана (мягкие, не блокируют разбор).