- Добавлен ConsoleLogger для подробного логирования этапов обработки аудиокниг в консоли. - Введен ConsolePresenter для форматированного вывода результатов сканирования в консоль. - Создан ProcessAudioBooksUseCase для обработки полного конвейера обработки аудиокниг, включая сканирование папок, извлечение метаданных, поиск торрентов и запись результатов. - Реализована проверка LLM для улучшения метаданных. - Добавлена обработка ошибок и логирование на всех этапах обработки.
132 lines
5.2 KiB
Go
132 lines
5.2 KiB
Go
// Package main демонстрирует использование валидации метаданных через OpenRouter.
|
||
// Этот файл является примером и не включён в основной build.
|
||
// Для запуска: go run examples/validate_metadata_example.go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"time"
|
||
|
||
"github.com/fofanov/genaudiobookinfo/internal/infrastructure"
|
||
)
|
||
|
||
func main() {
|
||
// Получаем API ключ из переменной окружения
|
||
apiKey := os.Getenv("OPENROUTER_API_KEY")
|
||
if apiKey == "" {
|
||
log.Fatal("Ошибка: установите переменную окружения OPENROUTER_API_KEY")
|
||
}
|
||
|
||
// Промпт для валидации метаданных
|
||
validationPrompt := `Ты — эксперт по метаданным русскоязычных аудиокниг. Твоя задача — проверить и исправить метаданные.
|
||
|
||
ПРАВИЛА ДЛЯ АВТОРА:
|
||
1. Автор ВСЕГДА должен быть в формате: "Фамилия Имя" (без отчества)
|
||
2. Если указано "Имя Фамилия" — переставь в правильный порядок
|
||
3. Если есть отчество (три слова) — убери его, оставь только "Фамилия Имя"
|
||
4. Если несколько авторов — обработай каждого по тем же правилам, раздели запятыми
|
||
|
||
ПРАВИЛА ДЛЯ НАЗВАНИЯ КНИГИ (title):
|
||
1. Убери номера серий, книг типа: "Книга 1", "01", "#1", "Том 2"
|
||
2. Убери название серии, если оно дублируется
|
||
3. Убери служебные слова: "Аудиокнига", "MP3", "читает"
|
||
4. Убери имя автора, если оно попало в название
|
||
5. Убери год издания из названия
|
||
6. Оставь только чистое название произведения
|
||
|
||
ФОРМАТ ОТВЕТА (строго JSON):
|
||
{
|
||
"author": "Исправленная Фамилия Имя",
|
||
"title": "Исправленное название без лишнего",
|
||
"author_fixed": true/false,
|
||
"title_fixed": true/false,
|
||
"changes": "краткое описание сделанных изменений"
|
||
}
|
||
|
||
Если исправления не требуются, верни исходные значения с флагами false.`
|
||
|
||
// Создаём клиент OpenRouter с промптом валидации
|
||
client := infrastructure.NewOpenRouterClient(infrastructure.OpenRouterConfig{
|
||
APIKey: apiKey,
|
||
BaseURL: "https://openrouter.ai/api/v1",
|
||
Timeout: 60 * time.Second,
|
||
Model: "openai/gpt-3.5-turbo",
|
||
Prompt: validationPrompt,
|
||
})
|
||
|
||
// Создаём контекст с таймаутом
|
||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||
defer cancel()
|
||
|
||
// Примеры некорректных метаданных
|
||
testCases := []struct {
|
||
author string
|
||
title string
|
||
desc string
|
||
}{
|
||
{
|
||
author: "Иванов Петр Сергеевич",
|
||
title: "Путешествие в неизвестность. Книга 1",
|
||
desc: "Отчество в авторе, номер книги в названии",
|
||
},
|
||
{
|
||
author: "Александр Пушкин",
|
||
title: "Евгений Онегин (Аудиокнига MP3)",
|
||
desc: "Имя-Фамилия, служебные слова в названии",
|
||
},
|
||
{
|
||
author: "Лев Николаевич Толстой",
|
||
title: "Война и мир. Том 1. 2020",
|
||
desc: "Полное имя с отчеством, номер тома и год",
|
||
},
|
||
{
|
||
author: "Стругацкий Аркадий",
|
||
title: "Пикник на обочине #2",
|
||
desc: "Некорректный номер книги",
|
||
},
|
||
{
|
||
author: "Булгаков Михаил",
|
||
title: "Мастер и Маргарита",
|
||
desc: "Корректные данные (не требуют исправления)",
|
||
},
|
||
}
|
||
|
||
fmt.Println("=== Валидация метаданных аудиокниг ===\n")
|
||
|
||
for i, tc := range testCases {
|
||
fmt.Printf("Пример %d: %s\n", i+1, tc.desc)
|
||
fmt.Printf("Исходные данные:\n")
|
||
fmt.Printf(" Автор: %s\n", tc.author)
|
||
fmt.Printf(" Название: %s\n", tc.title)
|
||
|
||
result, err := client.ValidateMetadata(ctx, tc.author, tc.title)
|
||
if err != nil {
|
||
log.Printf(" ❌ Ошибка валидации: %v\n\n", err)
|
||
continue
|
||
}
|
||
|
||
if result == nil {
|
||
fmt.Println(" ⚠️ Валидация отключена (нет API ключа или промпта)\n")
|
||
continue
|
||
}
|
||
|
||
fmt.Printf("\nРезультат:\n")
|
||
if result.AuthorFixed || result.TitleFixed {
|
||
fmt.Printf(" ✅ Исправлено:\n")
|
||
if result.AuthorFixed {
|
||
fmt.Printf(" Автор: %s\n", result.Author)
|
||
}
|
||
if result.TitleFixed {
|
||
fmt.Printf(" Название: %s\n", result.Title)
|
||
}
|
||
fmt.Printf(" 📝 Изменения: %s\n", result.Changes)
|
||
} else {
|
||
fmt.Printf(" ✓ Данные корректны, исправления не требуются\n")
|
||
}
|
||
fmt.Println()
|
||
}
|
||
}
|