Добавил выбор из кандидатов, если LLM не уверена в раскладке
This commit is contained in:
@@ -228,3 +228,92 @@ func (s *Store) DeleteFileLinksByBatch(ctx context.Context, batchID string) erro
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- Кандидаты базы метаданных (metadata_candidate) ---
|
||||
|
||||
// MetadataCandidate — строка таблицы metadata_candidate. provider/provider_id
|
||||
// хранят значения для тега Jellyfin (напр. TVMaze отдаёт внешний TVDB-id —
|
||||
// см. recognize), а не обязательно нативный id провайдера поиска.
|
||||
type MetadataCandidate struct {
|
||||
ID int64 `db:"id"`
|
||||
RecognitionID int64 `db:"recognition_id"`
|
||||
Provider string `db:"provider"`
|
||||
ProviderID string `db:"provider_id"`
|
||||
Title sql.NullString `db:"title"`
|
||||
Year sql.NullInt64 `db:"year"`
|
||||
Chosen bool `db:"chosen"`
|
||||
CreatedAt string `db:"created_at"`
|
||||
}
|
||||
|
||||
// CreateCandidates вставляет кандидатов распознавания одной транзакцией.
|
||||
func (s *Store) CreateCandidates(ctx context.Context, cands []MetadataCandidate) error {
|
||||
if len(cands) == 0 {
|
||||
return nil
|
||||
}
|
||||
tx, err := s.DB.BeginTxx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin tx: %w", err)
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
const q = `
|
||||
INSERT INTO metadata_candidate (recognition_id, provider, provider_id, title, year)
|
||||
VALUES (?, ?, ?, ?, ?)`
|
||||
for _, c := range cands {
|
||||
if _, err := tx.ExecContext(ctx, q,
|
||||
c.RecognitionID, c.Provider, c.ProviderID, c.Title, c.Year); err != nil {
|
||||
return fmt.Errorf("insert candidate: %w", err)
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("commit candidates: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListCandidatesByRecognition возвращает кандидатов попытки распознавания.
|
||||
func (s *Store) ListCandidatesByRecognition(ctx context.Context, recognitionID int64) ([]MetadataCandidate, error) {
|
||||
var out []MetadataCandidate
|
||||
if err := s.DB.SelectContext(ctx, &out,
|
||||
`SELECT * FROM metadata_candidate WHERE recognition_id = ? ORDER BY id`, recognitionID); err != nil {
|
||||
return nil, fmt.Errorf("list candidates: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GetCandidate возвращает кандидата по id либо (nil, nil).
|
||||
func (s *Store) GetCandidate(ctx context.Context, id int64) (*MetadataCandidate, error) {
|
||||
var c MetadataCandidate
|
||||
err := s.DB.GetContext(ctx, &c, `SELECT * FROM metadata_candidate WHERE id = ?`, id)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get candidate %d: %w", id, err)
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// SetCandidateChosen помечает кандидата выбранным, снимая отметку с прочих в
|
||||
// той же попытке распознавания.
|
||||
func (s *Store) SetCandidateChosen(ctx context.Context, recognitionID, candidateID int64) error {
|
||||
tx, err := s.DB.BeginTxx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin tx: %w", err)
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
if _, err := tx.ExecContext(ctx,
|
||||
`UPDATE metadata_candidate SET chosen = 0 WHERE recognition_id = ?`, recognitionID); err != nil {
|
||||
return fmt.Errorf("clear chosen: %w", err)
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx,
|
||||
`UPDATE metadata_candidate SET chosen = 1 WHERE id = ? AND recognition_id = ?`,
|
||||
candidateID, recognitionID); err != nil {
|
||||
return fmt.Errorf("set chosen: %w", err)
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("commit chosen: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user