# OpenRouter Integration Модуль интеграции с [OpenRouter API](https://openrouter.ai/) для использования различных LLM моделей в проекте GenAudioBookInfo. ## Описание OpenRouter предоставляет унифицированный API для доступа к различным языковым моделям (GPT-4, Claude, LLaMA и др.) через единый интерфейс, совместимый с OpenAI API. ## Архитектура Модуль реализован в соответствии с Clean Architecture: - **Domain Layer** (`internal/domain/`): - `ports.go` - интерфейс `LLMClient` - `llm.go` - доменные структуры `LLMRequest`, `LLMResponse`, `LLMMessage` - **Infrastructure Layer** (`internal/infrastructure/`): - `openrouter_client.go` - реализация HTTP клиента для OpenRouter API ## Конфигурация Добавьте настройки в `config.yaml`: ```yaml openrouter: api_key: "sk-or-v1-..." # Ваш API ключ с https://openrouter.ai/keys base_url: "https://openrouter.ai/api/v1" # Базовый URL (по умолчанию) timeout: 60s # Таймаут запросов model: "openai/gpt-3.5-turbo" # Модель по умолчанию prompt: | # System prompt для валидации метаданных (опционально) Ты — эксперт по метаданным аудиокниг. Проверяй формат автора (Фамилия Имя) и чистоту названий. ``` ### Получение API ключа 1. Зарегистрируйтесь на [openrouter.ai](https://openrouter.ai/) 2. Перейдите в раздел [Keys](https://openrouter.ai/keys) 3. Создайте новый API ключ 4. Добавьте ключ в `config.yaml` или переменную окружения `OPENROUTER_API_KEY` ## Использование ### Базовый пример ```go package main import ( "context" "fmt" "time" "github.com/fofanov/genaudiobookinfo/internal/domain" "github.com/fofanov/genaudiobookinfo/internal/infrastructure" ) func main() { // Создание клиента client := infrastructure.NewOpenRouterClient(infrastructure.OpenRouterConfig{ APIKey: "sk-or-v1-...", BaseURL: "https://openrouter.ai/api/v1", Timeout: 60 * time.Second, Model: "openai/gpt-3.5-turbo", }) // Создание запроса req := &domain.LLMRequest{ Model: "openai/gpt-3.5-turbo", Messages: []domain.LLMMessage{ { Role: "system", Content: "Ты — полезный ассистент.", }, { Role: "user", Content: "Привет! Как дела?", }, }, Temperature: 0.7, MaxTokens: 100, } // Выполнение запроса ctx := context.Background() resp, err := client.GenerateCompletion(ctx, req) if err != nil { panic(err) } // Получение ответа if len(resp.Choices) > 0 { fmt.Println(resp.Choices[0].Message.Content) fmt.Printf("Использовано токенов: %d\n", resp.Usage.TotalTokens) } } ``` ### Параметры запроса #### LLMRequest | Поле | Тип | Описание | |------|-----|----------| | `Model` | string | Идентификатор модели (например, `openai/gpt-4`) | | `Messages` | []LLMMessage | История диалога | | `Temperature` | float64 | Случайность генерации (0.0 - 2.0) | | `MaxTokens` | int | Максимум токенов в ответе | | `TopP` | float64 | Nucleus sampling параметр | | `FrequencyPenalty` | float64 | Штраф за повторяющиеся токены | | `PresencePenalty` | float64 | Штраф за уже встречавшиеся токены | #### LLMMessage | Поле | Тип | Описание | |------|-----|----------| | `Role` | string | Роль: `system`, `user`, или `assistant` | | `Content` | string | Текст сообщения | ### Доступные модели OpenRouter поддерживает множество моделей. Популярные варианты: - **OpenAI**: `openai/gpt-4`, `openai/gpt-3.5-turbo` - **Anthropic**: `anthropic/claude-3-opus`, `anthropic/claude-3-haiku` - **Google**: `google/gemini-pro` - **Meta**: `meta-llama/llama-3-70b-instruct` - **Mistral**: `mistralai/mistral-7b-instruct` Полный список: [openrouter.ai/docs#models](https://openrouter.ai/docs#models) ### Примеры использования #### Анализ метаданных аудиокниги ```go req := &domain.LLMRequest{ Model: "openai/gpt-4", Messages: []domain.LLMMessage{ { Role: "system", Content: "Ты — эксперт по метаданным аудиокниг.", }, { Role: "user", Content: "Нормализуй автора: Иванов Петр Сергеевич → формат 'Фамилия Имя'", }, }, Temperature: 0.3, MaxTokens: 50, } ``` #### Генерация описания ```go req := &domain.LLMRequest{ Model: "anthropic/claude-3-haiku", Messages: []domain.LLMMessage{ { Role: "system", Content: "Создавай краткие описания книг на русском языке.", }, { Role: "user", Content: fmt.Sprintf("Создай описание для: %s - %s", author, title), }, }, Temperature: 0.7, MaxTokens: 200, } ``` #### Валидация метаданных Модуль поддерживает автоматическую валидацию метаданных через метод `ValidateMetadata`: ```go // Создание клиента с промптом валидации client := infrastructure.NewOpenRouterClient(infrastructure.OpenRouterConfig{ APIKey: "sk-or-v1-...", Model: "openai/gpt-3.5-turbo", Prompt: validationPrompt, // см. config.yaml }) // Валидация метаданных result, err := client.ValidateMetadata(ctx, "Иванов Петр Сергеевич", "Путешествие. Книга 1") if err != nil { log.Fatal(err) } if result != nil { if result.AuthorFixed { fmt.Printf("Исправлен автор: %s\n", result.Author) // "Иванов Петр" } if result.TitleFixed { fmt.Printf("Исправлено название: %s\n", result.Title) // "Путешествие" } fmt.Printf("Изменения: %s\n", result.Changes) } ``` **Важно**: Валидация работает только если: - Указан `api_key` в конфигурации - Настроен `prompt` в конфигурации Если `api_key` пустой, метод вернет `nil` и валидация не выполнится. ## Продвинутые возможности ### Контроль таймаутов ```go ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() resp, err := client.GenerateCompletion(ctx, req) ``` ### Обработка ошибок ```go resp, err := client.GenerateCompletion(ctx, req) if err != nil { if ctx.Err() == context.DeadlineExceeded { fmt.Println("Таймаут запроса") } else { fmt.Printf("Ошибка API: %v\n", err) } return } if len(resp.Choices) == 0 { fmt.Println("Пустой ответ от API") return } ``` ### Настройка параметров генерации ```go req := &domain.LLMRequest{ Model: "openai/gpt-3.5-turbo", Messages: messages, Temperature: 0.8, // Выше = более креативно MaxTokens: 500, // Ограничение длины ответа TopP: 0.9, // Nucleus sampling FrequencyPenalty: 0.5, // Избегать повторов PresencePenalty: 0.3, // Разнообразие тем } ``` ## Запуск примеров В папке `examples/` находятся примеры использования: ### Базовое использование API ```bash # Установите API ключ export OPENROUTER_API_KEY="sk-or-v1-..." # Запустите пример общего использования go run examples/openrouter_example.go ``` ### Валидация метаданных аудиокниг ```bash # Запустите пример валидации метаданных go run examples/validate_metadata_example.go ``` Этот пример демонстрирует: - Исправление порядка "Имя Фамилия" → "Фамилия Имя" - Удаление отчества из имени автора - Очистку названий от номеров серий, томов, технических терминов - Обработку различных вариантов некорректных метаданных ## Стоимость использования OpenRouter работает по модели pay-as-you-go. Стоимость зависит от выбранной модели: - GPT-3.5 Turbo: ~$0.002 / 1K токенов - GPT-4: ~$0.03-0.06 / 1K токенов - Claude 3 Haiku: ~$0.25 / 1M токенов Следите за расходами на [openrouter.ai/activity](https://openrouter.ai/activity) ## Безопасность ⚠️ **Важно**: Никогда не коммитьте API ключи в репозиторий! Используйте: - Переменные окружения: `OPENROUTER_API_KEY` - Файл `.env` (добавьте в `.gitignore`) - Секреты CI/CD систем ## Лимиты и ограничения - **Rate limiting**: OpenRouter имеет лимиты на количество запросов - **Timeout**: Рекомендуется устанавливать таймаут 30-60 секунд - **Max tokens**: Учитывайте лимиты контекста моделей (обычно 4K-128K токенов) ## Устранение неполадок ### Ошибка: "API key не указан" Проверьте: 1. Ключ указан в `config.yaml` 2. Формат: `api_key: "sk-or-v1-..."` 3. Нет лишних пробелов или кавычек ### Ошибка: HTTP 401 Unauthorized - Проверьте валидность API ключа на [openrouter.ai/keys](https://openrouter.ai/keys) - Убедитесь, что ключ активен и не истёк ### Ошибка: HTTP 429 Too Many Requests - Слишком много запросов, снизьте частоту - Проверьте лимиты аккаунта ### Таймауты - Увеличьте `timeout` в конфигурации - Используйте более быстрые модели (например, `claude-3-haiku`) - Уменьшите `max_tokens` ## Дополнительные ресурсы - [OpenRouter Документация](https://openrouter.ai/docs) - [Список моделей](https://openrouter.ai/docs#models) - [Цены](https://openrouter.ai/docs#models) - [API Reference](https://openrouter.ai/docs#api)