kraken-llm


Namekraken-llm JSON
Version 0.1.1.post1 PyPI version JSON
download
home_pageNone
SummaryUniversal LLM framework with full OpenAI API support
upload_time2025-09-14 19:32:51
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords ai async llm machine-learning openai streaming
VCS
bugtrack_url
requirements openai outlines pydantic pydantic-settings httpx Pillow numpy python-dotenv typing-extensions
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Kraken LLM Framework

Универсальный Python фреймворк для работы с большими языковыми моделями (LLM) с полной поддержкой OpenAI API.

## Обзор

Kraken LLM Framework предоставляет единый интерфейс для различных типов взаимодействия с LLM, включая стандартные запросы, потоковую передачу, структурированный вывод, мультимодальность и работу с речью.

### Ключевые особенности

- **Универсальный клиент**: UniversalLLMClient объединяет все возможности в едином интерфейсе
- **Полная поддержка OpenAI API**: chat completions, streaming, function calling, tool calling
- **Структурированный вывод**: Валидация Pydantic моделей с интеграцией Outlines и нативной поддержкой OpenAI
- **Асинхронность**: Построен на AsyncOpenAI для высокой производительности
- **Типобезопасность**: Полная поддержка type hints и IDE
- **Простая конфигурация**: Pydantic Settings с поддержкой переменных окружения
- **Расширяемость**: Архитектура плагинов для пользовательских функций и инструментов
- **Мультимодальность**: Поддержка текста, изображений, аудио и видео
- **Речевые технологии**: ASR (распознавание речи), TTS (синтез речи), диаризация спикеров
- **Рассуждающие модели**: Поддержка Chain of Thought и нативных thinking токенов
- **Адаптивность**: Автоматический выбор оптимального режима работы
- **Анализ возможностей**: Автоматическое определение возможностей моделей

## Установка

### Базовая установка

```bash
# Пакетом из PyPI
pip install kraken-llm

# Из исходников
git clone https://github.com/antonshalin76/kraken_llm
cd kraken-llm
pip install -e .

# С дополнительными зависимостями
pip install -e .[dev]  # Для разработки
pip install -e .[all]  # Все зависимости
```

### Системные требования

- Python 3.10+
- AsyncOpenAI 1.0.0+
- Pydantic 2.0.0+
- Outlines 0.0.30+
- Pillow 10.0.0+ (для работы с изображениями)

## Быстрый старт

### Простейший пример

```python
from kraken_llm import create_universal_client

async with create_universal_client() as client:
    response = await client.chat_completion([
        {"role": "user", "content": "Привет, мир!"}
    ])
    print(response)
```

### Анализ возможностей моделей

Перед началом работы рекомендуется проанализировать возможности ваших моделей:

```bash
# Быстрый анализ
python3 model_capabilities_analyzer.py --quick

# Полный анализ с Markdown отчетом
python3 model_capabilities_analyzer.py --output markdown

# Через Makefile
make capabilities-analyze-quick
```

## Конфигурация

### Переменные окружения

Все параметры конфигурации могут быть заданы через переменные окружения с префиксом `LLM_`:

```bash
export LLM_ENDPOINT="http://localhost:8080"
export LLM_API_KEY="your-api-key"
export LLM_MODEL="chat"
export LLM_TEMPERATURE=0.7
export LLM_MAX_TOKENS=2000
```

### Файл .env

```env
LLM_ENDPOINT=http://localhost:8080
LLM_API_KEY=your-api-key
LLM_MODEL=chat
LLM_TEMPERATURE=0.7
LLM_MAX_TOKENS=2000
LLM_STREAM=false
LLM_OUTLINES_SO_MODE=true
```

### Класс LLMConfig

```python
from kraken_llm import LLMConfig

config = LLMConfig(
    endpoint="http://localhost:8080",
    api_key="your-api-key",
    model="chat",
    temperature=0.7,
    max_tokens=2000
)
```

## Универсальный клиент

### Основные возможности

UniversalLLMClient - это универсальный клиент, который объединяет все возможности Kraken LLM в едином интерфейсе:

```python
from kraken_llm import (
    create_universal_client,
    create_basic_client,
    create_advanced_client,
    create_full_client,
    UniversalCapability
)

# Базовый клиент (chat + streaming)
async with create_basic_client() as client:
    response = await client.chat_completion([
        {"role": "user", "content": "Привет!"}
    ])

# Продвинутый клиент (+ structured output, function calling, reasoning)
async with create_advanced_client() as client:
    # Автоматический fallback для structured output
    from pydantic import BaseModel
    
    class Task(BaseModel):
        title: str
        priority: int
    
    task = await client.chat_completion_structured([
        {"role": "user", "content": "Создай задачу изучить Python"}
    ], response_model=Task)

# Полнофункциональный клиент (все возможности)
async with create_full_client() as client:
    capabilities = client.get_available_capabilities()
    print(f"Доступные возможности: {capabilities}")
```

### Создание на основе анализа возможностей

```python
from kraken_llm import create_universal_client_from_report

# Анализируем возможности модели
from model_capabilities_analyzer import ModelCapabilitiesAnalyzer

analyzer = ModelCapabilitiesAnalyzer()
report = await analyzer.analyze_all_models()

# Создаем оптимальный клиент
async with create_universal_client_from_report(report) as client:
    # Клиент автоматически настроен под возможности модели
    response = await client.chat_completion([
        {"role": "user", "content": "Тест"}
    ])
```

### Кастомная конфигурация

```python
from kraken_llm import create_universal_client, UniversalCapability

# Выбираем только нужные возможности
capabilities = {
    UniversalCapability.CHAT_COMPLETION,
    UniversalCapability.STREAMING,
    UniversalCapability.STRUCTURED_OUTPUT,
    UniversalCapability.FUNCTION_CALLING
}

async with create_universal_client(capabilities=capabilities) as client:
    # Используем только выбранные возможности
    pass
```

## Типы клиентов

### Специализированные клиенты

Kraken предоставляет специализированные клиенты для различных задач:

```python
from kraken_llm import (
    create_standard_client,      # Базовые операции
    create_streaming_client,     # Потоковая передача
    create_structured_client,    # Структурированный вывод
    create_reasoning_client,     # Рассуждающие модели
    create_multimodal_client,    # Мультимодальность
    create_adaptive_client,      # Адаптивный режим
    create_asr_client,          # Речевые технологии
    create_embeddings_client,   # Векторные представления
)

# Стандартный клиент
async with create_standard_client() as client:
    response = await client.chat_completion([
        {"role": "user", "content": "Привет"}
    ])

# Потоковый клиент
async with create_streaming_client() as client:
    async for chunk in client.chat_completion_stream([
        {"role": "user", "content": "Расскажи историю"}
    ]):
        print(chunk, end="", flush=True)
```

### Фабрика клиентов

```python
from kraken_llm import ClientFactory, create_client

# Автоматический выбор типа клиента
client = create_client(
    stream=True  # Автоматически выберет StreamingLLMClient
)

# Явное указание типа
client = ClientFactory.create_client(
    client_type="structured",
    endpoint="http://localhost:8080"
)
```

## Структурированный вывод

### Автоматический fallback

UniversalLLMClient автоматически выбирает оптимальный режим для structured output:

```python
from pydantic import BaseModel

class Person(BaseModel):
    name: str
    age: int
    skills: list[str]

async with create_universal_client() as client:
    # Автоматически пробует:
    # 1. Нативный OpenAI structured output
    # 2. Outlines режим
    # 3. Fallback через JSON parsing
    person = await client.chat_completion_structured([
        {"role": "user", "content": "Создай профиль разработчика"}
    ], response_model=Person)
```

### Режимы работы

```python
async with create_structured_client() as client:
    # Принудительное использование Outlines
    person = await client.chat_completion_structured(
        messages=[{"role": "user", "content": "Создай профиль"}],
        response_model=Person,
        mode="outlines"
    )
    
    # Использование нативного режима OpenAI
    person = await client.chat_completion_structured(
        messages=[{"role": "user", "content": "Создай профиль"}],
        response_model=Person,
        mode="native"
    )
```

## Рассуждающие модели

### Chain of Thought

```python
from kraken_llm import create_reasoning_client, ReasoningConfig

config = ReasoningConfig(
    model_type="prompt_based",
    enable_cot=True,
    max_reasoning_steps=10
)

async with create_reasoning_client(reasoning_config=config) as client:
    response = await client.reasoning_completion([
        {"role": "user", "content": "Реши: 15 * 23 + 45"}
    ], problem_type="math")
    
    # Доступ к шагам рассуждения
    for step in response.steps:
        print(f"Шаг {step.step_number}: {step.thought}")
```

### Native Thinking

```python
config = ReasoningConfig(
    model_type="native_thinking",
    enable_thinking=True,
    thinking_max_tokens=5000
)

async with create_reasoning_client(reasoning_config=config) as client:
    response = await client.reasoning_completion([
        {"role": "user", "content": "Объясни квантовую физику"}
    ])
    
    # Доступ к thinking блокам
    if response.thinking_blocks:
        for block in response.thinking_blocks:
            print(f"Thinking: {block.content}")
```

## Мультимодальность

### Анализ изображений

```python
from kraken_llm import create_multimodal_client
from pathlib import Path

async with create_multimodal_client() as client:
    # Анализ изображения
    response = await client.vision_completion(
        text_prompt="Опиши что видишь на изображении",
        images="photo.jpg"
    )
    
    # Анализ нескольких изображений
    response = await client.vision_completion(
        text_prompt="Сравни эти изображения",
        images=["photo1.jpg", "photo2.jpg"]
    )
```

### Работа с аудио и видео

```python
# Обработка аудио
response = await client.audio_completion(
    text_prompt="Проанализируй содержание аудио",
    audio_files="recording.wav",
    task_type="analysis"
)

# Анализ видео
response = await client.video_completion(
    text_prompt="Опиши что происходит в видео",
    video_files="video.mp4"
)
```

## Речевые технологии

### ASR Client

```python
from kraken_llm import create_asr_client

async with create_asr_client() as client:
    # Распознавание речи
    result = await client.speech_to_text(
        audio_file="recording.wav",
        language="ru"
    )
    
    # Синтез речи
    audio_data = await client.text_to_speech(
        text="Привет, как дела?",
        voice="alloy"
    )
    
    # Диаризация спикеров
    diarization = await client.speaker_diarization(
        audio_file="meeting.wav",
        num_speakers=3
    )
```

## Function и Tool Calling

### Регистрация функций

```python
def get_weather(city: str) -> str:
    """Получить погоду в указанном городе."""
    return f"В городе {city} сейчас солнечно, +20°C"

async with create_universal_client() as client:
    # Регистрация функции
    client.register_function(
        name="get_weather",
        function=get_weather,
        description="Получить текущую погоду"
    )
    
    # Использование
    response = await client.chat_completion([
        {"role": "user", "content": "Какая погода в Москве?"}
    ])
```

### Декораторы для функций

```python
from kraken_llm.tools import register_function

@register_function("calculate", "Выполнить математические вычисления")
async def calculate(expression: str) -> float:
    """Безопасное вычисление математических выражений."""
    return eval(expression)  # В реальности используйте безопасный парсер
```

## Векторные представления

### Embeddings Client

```python
from kraken_llm import create_embeddings_client

async with create_embeddings_client() as client:
    # Получение embeddings
    embeddings = await client.create_embeddings([
        "Первый текст для векторизации",
        "Второй текст для векторизации"
    ])
    
    # Поиск похожих текстов
    similar = await client.similarity_search(
        query_text="поисковый запрос",
        candidate_texts=["текст 1", "текст 2", "текст 3"],
        top_k=2
    )
```

## Потоковые операции

### Streaming Handler

```python
from kraken_llm.streaming import StreamHandler, StreamAggregator

# Обработка потока
handler = StreamHandler()
aggregator = StreamAggregator()

async for chunk_data in handler.process_stream(response_stream):
    if chunk_data["type"] == "content":
        aggregator.add_content(chunk_data["data"])
    elif chunk_data["type"] == "function_call_complete":
        print(f"Function call: {chunk_data['data']}")

# Получение полного контента
full_content = aggregator.get_aggregated_content()
```

## Анализ возможностей моделей

### ModelCapabilitiesAnalyzer

```python
from model_capabilities_analyzer import ModelCapabilitiesAnalyzer

# Создание анализатора
analyzer = ModelCapabilitiesAnalyzer()

# Быстрый анализ
report = await analyzer.analyze_all_models(quick_mode=True)

# Полный анализ
report = await analyzer.analyze_all_models(quick_mode=False)

# Сохранение отчета
analyzer.save_report(report, output_format="markdown", filename="capabilities.md")
analyzer.save_report(report, output_format="json", filename="capabilities.json")
```

### Использование результатов анализа

```python
# Создание клиента на основе анализа
async with create_universal_client_from_report(report, model_name="my_model") as client:
    # Клиент настроен под возможности конкретной модели
    capabilities = client.get_available_capabilities()
    print(f"Подтвержденные возможности: {capabilities}")
```

## Обработка ошибок

### Иерархия исключений

```python
from kraken_llm.exceptions import (
    KrakenError,           # Базовое исключение
    APIError,              # Ошибки API
    ValidationError,       # Ошибки валидации
    NetworkError,          # Сетевые ошибки
    AuthenticationError,   # Ошибки аутентификации
    RateLimitError,        # Превышение лимитов
)

try:
    response = await client.chat_completion([
        {"role": "user", "content": "Тест"}
    ])
except RateLimitError as e:
    print(f"Превышен лимит запросов: {e}")
    print(f"Повторить через: {e.retry_after} секунд")
except AuthenticationError as e:
    print(f"Ошибка аутентификации: {e}")
except ValidationError as e:
    print(f"Ошибка валидации: {e}")
    for detail in e.context.get("error_details", []):
        print(f"Поле {detail['field']}: {detail['message']}")
except KrakenError as e:
    print(f"Общая ошибка Kraken: {e}")
```

## Утилиты

### Работа с медиа файлами

```python
from kraken_llm.utils.media import MediaUtils

# Валидация медиа файла
validation = MediaUtils.validate_media_file(
    "image.jpg",
    media_type="image",
    max_size=10 * 1024 * 1024
)

# Изменение размера изображения
result = MediaUtils.resize_image(
    "large_image.jpg",
    "resized_image.jpg",
    max_width=1024,
    max_height=1024
)

# Создание data URL
data_url = MediaUtils.create_data_url("image.jpg")
```

## Тестирование

### Запуск тестов

```bash
# Все тесты
make test

# Только unit тесты
make test-unit

# Только integration тесты
make test-integration

# С покрытием
make test-coverage
```

### Тестирование возможностей

```python
async with create_universal_client() as client:
    # Автоматическое тестирование всех возможностей
    test_results = await client.test_capabilities()
    
    for capability, result in test_results.items():
        status = "✅" if result else "❌"
        print(f"{status} {capability}")
```

## Примеры использования

В папке `examples/` находятся подробные примеры:

- `quick_universal_example.py` - Быстрый старт с универсальным клиентом
- `universal_client_example.py` - Подробные примеры использования
- `complete_workflow_example.py` - Полный рабочий процесс
- `adaptive_capabilities_example.py` - Адаптивные возможности
- `structured_output_fallback_example.py` - Структурированный вывод с fallback
- `reasoning_example.py` - Рассуждающие модели
- `multimodal_example.py` - Мультимодальные операции
- `streaming_example.py` - Потоковые операции
- `function_tool_example.py` - Функции и инструменты

## Архитектура

### Структура проекта

```
kraken_llm/
├── client/           # LLM клиенты
│   ├── base.py       # Базовый клиент
│   ├── standard.py   # Стандартный клиент
│   ├── streaming.py  # Потоковый клиент
│   ├── structured.py # Структурированный вывод
│   ├── reasoning.py  # Рассуждающие модели
│   ├── multimodal.py # Мультимодальный клиент
│   ├── adaptive.py   # Адаптивный клиент
│   ├── asr.py        # Речевые технологии
│   ├── embeddings.py # Векторные представления
│   ├── universal.py  # Универсальный клиент
│   └── factory.py    # Фабрика клиентов
├── tools/            # Система функций и инструментов
├── streaming/        # Потоковые операции
├── structured/       # Структурированный вывод
├── utils/           # Утилиты (медиа, логирование)
├── exceptions/       # Обработка ошибок
└── models/          # Модели данных
```

### Принципы архитектуры

1. **Модульность**: Каждый компонент имеет четко определенную ответственность
2. **Расширяемость**: Легко добавлять новые типы клиентов и функциональность
3. **Типобезопасность**: Полная поддержка type hints во всех компонентах
4. **Асинхронность**: Все операции построены на async/await
5. **Конфигурируемость**: Гибкая система настроек через Pydantic Settings
6. **Обработка ошибок**: Иерархическая система исключений с контекстом
7. **Автоопределение**: Автоматический выбор подходящего клиента через фабрику

## Лицензия

MIT License - делайте что хотите ;-). См. файл [LICENSE](LICENSE) для подробностей.

## Поддержка

- Примеры: [examples/](examples/)
- Тесты: [tests/](tests/)
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "kraken-llm",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "ai, async, llm, machine-learning, openai, streaming",
    "author": null,
    "author_email": "Anton Shalin <anton.shalin@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/d0/e7/298deff580ccebeee6f4772122058e3b6529947571de805fd88d84b00ec7/kraken_llm-0.1.1.post1.tar.gz",
    "platform": null,
    "description": "# Kraken LLM Framework\n\n\u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 Python \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u043c\u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 (LLM) \u0441 \u043f\u043e\u043b\u043d\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 OpenAI API.\n\n## \u041e\u0431\u0437\u043e\u0440\n\nKraken LLM Framework \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 LLM, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u0443\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434, \u043c\u0443\u043b\u044c\u0442\u0438\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0440\u0435\u0447\u044c\u044e.\n\n### \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438\n\n- **\u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442**: UniversalLLMClient \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432 \u0435\u0434\u0438\u043d\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435\n- **\u041f\u043e\u043b\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 OpenAI API**: chat completions, streaming, function calling, tool calling\n- **\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434**: \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f Pydantic \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0435\u0439 Outlines \u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 OpenAI\n- **\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c**: \u041f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430 AsyncOpenAI \u0434\u043b\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438\n- **\u0422\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c**: \u041f\u043e\u043b\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 type hints \u0438 IDE\n- **\u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f**: Pydantic Settings \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\n- **\u0420\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c**: \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432\n- **\u041c\u0443\u043b\u044c\u0442\u0438\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c**: \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0435\u043a\u0441\u0442\u0430, \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0430\u0443\u0434\u0438\u043e \u0438 \u0432\u0438\u0434\u0435\u043e\n- **\u0420\u0435\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438**: ASR (\u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0447\u0438), TTS (\u0441\u0438\u043d\u0442\u0435\u0437 \u0440\u0435\u0447\u0438), \u0434\u0438\u0430\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043f\u0438\u043a\u0435\u0440\u043e\u0432\n- **\u0420\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438**: \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 Chain of Thought \u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 thinking \u0442\u043e\u043a\u0435\u043d\u043e\u0432\n- **\u0410\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c**: \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b\n- **\u0410\u043d\u0430\u043b\u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439**: \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0435\u0439\n\n## \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n\n### \u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n\n```bash\n# \u041f\u0430\u043a\u0435\u0442\u043e\u043c \u0438\u0437 PyPI\npip install kraken-llm\n\n# \u0418\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432\ngit clone https://github.com/antonshalin76/kraken_llm\ncd kraken-llm\npip install -e .\n\n# \u0421 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438\npip install -e .[dev]  # \u0414\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438\npip install -e .[all]  # \u0412\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\n```\n\n### \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\n\n- Python 3.10+\n- AsyncOpenAI 1.0.0+\n- Pydantic 2.0.0+\n- Outlines 0.0.30+\n- Pillow 10.0.0+ (\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u043c\u0438)\n\n## \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\n\n### \u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440\n\n```python\nfrom kraken_llm import create_universal_client\n\nasync with create_universal_client() as client:\n    response = await client.chat_completion([\n        {\"role\": \"user\", \"content\": \"\u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0438\u0440!\"}\n    ])\n    print(response)\n```\n\n### \u0410\u043d\u0430\u043b\u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0435\u0439\n\n\u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u0430\u0448\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439:\n\n```bash\n# \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437\npython3 model_capabilities_analyzer.py --quick\n\n# \u041f\u043e\u043b\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0441 Markdown \u043e\u0442\u0447\u0435\u0442\u043e\u043c\npython3 model_capabilities_analyzer.py --output markdown\n\n# \u0427\u0435\u0440\u0435\u0437 Makefile\nmake capabilities-analyze-quick\n```\n\n## \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\n\n### \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\n\n\u0412\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u044b \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c `LLM_`:\n\n```bash\nexport LLM_ENDPOINT=\"http://localhost:8080\"\nexport LLM_API_KEY=\"your-api-key\"\nexport LLM_MODEL=\"chat\"\nexport LLM_TEMPERATURE=0.7\nexport LLM_MAX_TOKENS=2000\n```\n\n### \u0424\u0430\u0439\u043b .env\n\n```env\nLLM_ENDPOINT=http://localhost:8080\nLLM_API_KEY=your-api-key\nLLM_MODEL=chat\nLLM_TEMPERATURE=0.7\nLLM_MAX_TOKENS=2000\nLLM_STREAM=false\nLLM_OUTLINES_SO_MODE=true\n```\n\n### \u041a\u043b\u0430\u0441\u0441 LLMConfig\n\n```python\nfrom kraken_llm import LLMConfig\n\nconfig = LLMConfig(\n    endpoint=\"http://localhost:8080\",\n    api_key=\"your-api-key\",\n    model=\"chat\",\n    temperature=0.7,\n    max_tokens=2000\n)\n```\n\n## \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\n### \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\n\nUniversalLLMClient - \u044d\u0442\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 Kraken LLM \u0432 \u0435\u0434\u0438\u043d\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435:\n\n```python\nfrom kraken_llm import (\n    create_universal_client,\n    create_basic_client,\n    create_advanced_client,\n    create_full_client,\n    UniversalCapability\n)\n\n# \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 (chat + streaming)\nasync with create_basic_client() as client:\n    response = await client.chat_completion([\n        {\"role\": \"user\", \"content\": \"\u041f\u0440\u0438\u0432\u0435\u0442!\"}\n    ])\n\n# \u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 (+ structured output, function calling, reasoning)\nasync with create_advanced_client() as client:\n    # \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 fallback \u0434\u043b\u044f structured output\n    from pydantic import BaseModel\n    \n    class Task(BaseModel):\n        title: str\n        priority: int\n    \n    task = await client.chat_completion_structured([\n        {\"role\": \"user\", \"content\": \"\u0421\u043e\u0437\u0434\u0430\u0439 \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u0437\u0443\u0447\u0438\u0442\u044c Python\"}\n    ], response_model=Task)\n\n# \u041f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 (\u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438)\nasync with create_full_client() as client:\n    capabilities = client.get_available_capabilities()\n    print(f\"\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438: {capabilities}\")\n```\n\n### \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439\n\n```python\nfrom kraken_llm import create_universal_client_from_report\n\n# \u0410\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0435\u043b\u0438\nfrom model_capabilities_analyzer import ModelCapabilitiesAnalyzer\n\nanalyzer = ModelCapabilitiesAnalyzer()\nreport = await analyzer.analyze_all_models()\n\n# \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\nasync with create_universal_client_from_report(report) as client:\n    # \u041a\u043b\u0438\u0435\u043d\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u043e\u0434 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0435\u043b\u0438\n    response = await client.chat_completion([\n        {\"role\": \"user\", \"content\": \"\u0422\u0435\u0441\u0442\"}\n    ])\n```\n\n### \u041a\u0430\u0441\u0442\u043e\u043c\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\n\n```python\nfrom kraken_llm import create_universal_client, UniversalCapability\n\n# \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\ncapabilities = {\n    UniversalCapability.CHAT_COMPLETION,\n    UniversalCapability.STREAMING,\n    UniversalCapability.STRUCTURED_OUTPUT,\n    UniversalCapability.FUNCTION_CALLING\n}\n\nasync with create_universal_client(capabilities=capabilities) as client:\n    # \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\n    pass\n```\n\n## \u0422\u0438\u043f\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432\n\n### \u0421\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b\n\nKraken \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447:\n\n```python\nfrom kraken_llm import (\n    create_standard_client,      # \u0411\u0430\u0437\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438\n    create_streaming_client,     # \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430\n    create_structured_client,    # \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434\n    create_reasoning_client,     # \u0420\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438\n    create_multimodal_client,    # \u041c\u0443\u043b\u044c\u0442\u0438\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\n    create_adaptive_client,      # \u0410\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c\n    create_asr_client,          # \u0420\u0435\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438\n    create_embeddings_client,   # \u0412\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\n)\n\n# \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\nasync with create_standard_client() as client:\n    response = await client.chat_completion([\n        {\"role\": \"user\", \"content\": \"\u041f\u0440\u0438\u0432\u0435\u0442\"}\n    ])\n\n# \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\nasync with create_streaming_client() as client:\n    async for chunk in client.chat_completion_stream([\n        {\"role\": \"user\", \"content\": \"\u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u044e\"}\n    ]):\n        print(chunk, end=\"\", flush=True)\n```\n\n### \u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432\n\n```python\nfrom kraken_llm import ClientFactory, create_client\n\n# \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u0442\u0438\u043f\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\nclient = create_client(\n    stream=True  # \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 StreamingLLMClient\n)\n\n# \u042f\u0432\u043d\u043e\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u0430\nclient = ClientFactory.create_client(\n    client_type=\"structured\",\n    endpoint=\"http://localhost:8080\"\n)\n```\n\n## \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434\n\n### \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 fallback\n\nUniversalLLMClient \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0434\u043b\u044f structured output:\n\n```python\nfrom pydantic import BaseModel\n\nclass Person(BaseModel):\n    name: str\n    age: int\n    skills: list[str]\n\nasync with create_universal_client() as client:\n    # \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u043e\u0431\u0443\u0435\u0442:\n    # 1. \u041d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 OpenAI structured output\n    # 2. Outlines \u0440\u0435\u0436\u0438\u043c\n    # 3. Fallback \u0447\u0435\u0440\u0435\u0437 JSON parsing\n    person = await client.chat_completion_structured([\n        {\"role\": \"user\", \"content\": \"\u0421\u043e\u0437\u0434\u0430\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\"}\n    ], response_model=Person)\n```\n\n### \u0420\u0435\u0436\u0438\u043c\u044b \u0440\u0430\u0431\u043e\u0442\u044b\n\n```python\nasync with create_structured_client() as client:\n    # \u041f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Outlines\n    person = await client.chat_completion_structured(\n        messages=[{\"role\": \"user\", \"content\": \"\u0421\u043e\u0437\u0434\u0430\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c\"}],\n        response_model=Person,\n        mode=\"outlines\"\n    )\n    \n    # \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 OpenAI\n    person = await client.chat_completion_structured(\n        messages=[{\"role\": \"user\", \"content\": \"\u0421\u043e\u0437\u0434\u0430\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c\"}],\n        response_model=Person,\n        mode=\"native\"\n    )\n```\n\n## \u0420\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438\n\n### Chain of Thought\n\n```python\nfrom kraken_llm import create_reasoning_client, ReasoningConfig\n\nconfig = ReasoningConfig(\n    model_type=\"prompt_based\",\n    enable_cot=True,\n    max_reasoning_steps=10\n)\n\nasync with create_reasoning_client(reasoning_config=config) as client:\n    response = await client.reasoning_completion([\n        {\"role\": \"user\", \"content\": \"\u0420\u0435\u0448\u0438: 15 * 23 + 45\"}\n    ], problem_type=\"math\")\n    \n    # \u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0448\u0430\u0433\u0430\u043c \u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044f\n    for step in response.steps:\n        print(f\"\u0428\u0430\u0433 {step.step_number}: {step.thought}\")\n```\n\n### Native Thinking\n\n```python\nconfig = ReasoningConfig(\n    model_type=\"native_thinking\",\n    enable_thinking=True,\n    thinking_max_tokens=5000\n)\n\nasync with create_reasoning_client(reasoning_config=config) as client:\n    response = await client.reasoning_completion([\n        {\"role\": \"user\", \"content\": \"\u041e\u0431\u044a\u044f\u0441\u043d\u0438 \u043a\u0432\u0430\u043d\u0442\u043e\u0432\u0443\u044e \u0444\u0438\u0437\u0438\u043a\u0443\"}\n    ])\n    \n    # \u0414\u043e\u0441\u0442\u0443\u043f \u043a thinking \u0431\u043b\u043e\u043a\u0430\u043c\n    if response.thinking_blocks:\n        for block in response.thinking_blocks:\n            print(f\"Thinking: {block.content}\")\n```\n\n## \u041c\u0443\u043b\u044c\u0442\u0438\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\n\n### \u0410\u043d\u0430\u043b\u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439\n\n```python\nfrom kraken_llm import create_multimodal_client\nfrom pathlib import Path\n\nasync with create_multimodal_client() as client:\n    # \u0410\u043d\u0430\u043b\u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\n    response = await client.vision_completion(\n        text_prompt=\"\u041e\u043f\u0438\u0448\u0438 \u0447\u0442\u043e \u0432\u0438\u0434\u0438\u0448\u044c \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438\",\n        images=\"photo.jpg\"\n    )\n    \n    # \u0410\u043d\u0430\u043b\u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439\n    response = await client.vision_completion(\n        text_prompt=\"\u0421\u0440\u0430\u0432\u043d\u0438 \u044d\u0442\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\",\n        images=[\"photo1.jpg\", \"photo2.jpg\"]\n    )\n```\n\n### \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0430\u0443\u0434\u0438\u043e \u0438 \u0432\u0438\u0434\u0435\u043e\n\n```python\n# \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0430\u0443\u0434\u0438\u043e\nresponse = await client.audio_completion(\n    text_prompt=\"\u041f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0430\u0443\u0434\u0438\u043e\",\n    audio_files=\"recording.wav\",\n    task_type=\"analysis\"\n)\n\n# \u0410\u043d\u0430\u043b\u0438\u0437 \u0432\u0438\u0434\u0435\u043e\nresponse = await client.video_completion(\n    text_prompt=\"\u041e\u043f\u0438\u0448\u0438 \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u0432\u0438\u0434\u0435\u043e\",\n    video_files=\"video.mp4\"\n)\n```\n\n## \u0420\u0435\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438\n\n### ASR Client\n\n```python\nfrom kraken_llm import create_asr_client\n\nasync with create_asr_client() as client:\n    # \u0420\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0447\u0438\n    result = await client.speech_to_text(\n        audio_file=\"recording.wav\",\n        language=\"ru\"\n    )\n    \n    # \u0421\u0438\u043d\u0442\u0435\u0437 \u0440\u0435\u0447\u0438\n    audio_data = await client.text_to_speech(\n        text=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u043a\u0430\u043a \u0434\u0435\u043b\u0430?\",\n        voice=\"alloy\"\n    )\n    \n    # \u0414\u0438\u0430\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043f\u0438\u043a\u0435\u0440\u043e\u0432\n    diarization = await client.speaker_diarization(\n        audio_file=\"meeting.wav\",\n        num_speakers=3\n    )\n```\n\n## Function \u0438 Tool Calling\n\n### \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439\n\n```python\ndef get_weather(city: str) -> str:\n    \"\"\"\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0433\u043e\u0434\u0443 \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c \u0433\u043e\u0440\u043e\u0434\u0435.\"\"\"\n    return f\"\u0412 \u0433\u043e\u0440\u043e\u0434\u0435 {city} \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u043e\u043b\u043d\u0435\u0447\u043d\u043e, +20\u00b0C\"\n\nasync with create_universal_client() as client:\n    # \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438\n    client.register_function(\n        name=\"get_weather\",\n        function=get_weather,\n        description=\"\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043f\u043e\u0433\u043e\u0434\u0443\"\n    )\n    \n    # \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\n    response = await client.chat_completion([\n        {\"role\": \"user\", \"content\": \"\u041a\u0430\u043a\u0430\u044f \u043f\u043e\u0433\u043e\u0434\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435?\"}\n    ])\n```\n\n### \u0414\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439\n\n```python\nfrom kraken_llm.tools import register_function\n\n@register_function(\"calculate\", \"\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f\")\nasync def calculate(expression: str) -> float:\n    \"\"\"\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.\"\"\"\n    return eval(expression)  # \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0439 \u043f\u0430\u0440\u0441\u0435\u0440\n```\n\n## \u0412\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\n\n### Embeddings Client\n\n```python\nfrom kraken_llm import create_embeddings_client\n\nasync with create_embeddings_client() as client:\n    # \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 embeddings\n    embeddings = await client.create_embeddings([\n        \"\u041f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438\",\n        \"\u0412\u0442\u043e\u0440\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438\"\n    ])\n    \n    # \u041f\u043e\u0438\u0441\u043a \u043f\u043e\u0445\u043e\u0436\u0438\u0445 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\n    similar = await client.similarity_search(\n        query_text=\"\u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\",\n        candidate_texts=[\"\u0442\u0435\u043a\u0441\u0442 1\", \"\u0442\u0435\u043a\u0441\u0442 2\", \"\u0442\u0435\u043a\u0441\u0442 3\"],\n        top_k=2\n    )\n```\n\n## \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438\n\n### Streaming Handler\n\n```python\nfrom kraken_llm.streaming import StreamHandler, StreamAggregator\n\n# \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\nhandler = StreamHandler()\naggregator = StreamAggregator()\n\nasync for chunk_data in handler.process_stream(response_stream):\n    if chunk_data[\"type\"] == \"content\":\n        aggregator.add_content(chunk_data[\"data\"])\n    elif chunk_data[\"type\"] == \"function_call_complete\":\n        print(f\"Function call: {chunk_data['data']}\")\n\n# \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430\nfull_content = aggregator.get_aggregated_content()\n```\n\n## \u0410\u043d\u0430\u043b\u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0435\u0439\n\n### ModelCapabilitiesAnalyzer\n\n```python\nfrom model_capabilities_analyzer import ModelCapabilitiesAnalyzer\n\n# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430\nanalyzer = ModelCapabilitiesAnalyzer()\n\n# \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437\nreport = await analyzer.analyze_all_models(quick_mode=True)\n\n# \u041f\u043e\u043b\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437\nreport = await analyzer.analyze_all_models(quick_mode=False)\n\n# \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043e\u0442\u0447\u0435\u0442\u0430\nanalyzer.save_report(report, output_format=\"markdown\", filename=\"capabilities.md\")\nanalyzer.save_report(report, output_format=\"json\", filename=\"capabilities.json\")\n```\n\n### \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\n\n```python\n# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\nasync with create_universal_client_from_report(report, model_name=\"my_model\") as client:\n    # \u041a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u043e\u0434 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438\n    capabilities = client.get_available_capabilities()\n    print(f\"\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438: {capabilities}\")\n```\n\n## \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a\n\n### \u0418\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439\n\n```python\nfrom kraken_llm.exceptions import (\n    KrakenError,           # \u0411\u0430\u0437\u043e\u0432\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\n    APIError,              # \u041e\u0448\u0438\u0431\u043a\u0438 API\n    ValidationError,       # \u041e\u0448\u0438\u0431\u043a\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438\n    NetworkError,          # \u0421\u0435\u0442\u0435\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438\n    AuthenticationError,   # \u041e\u0448\u0438\u0431\u043a\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438\n    RateLimitError,        # \u041f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u0435 \u043b\u0438\u043c\u0438\u0442\u043e\u0432\n)\n\ntry:\n    response = await client.chat_completion([\n        {\"role\": \"user\", \"content\": \"\u0422\u0435\u0441\u0442\"}\n    ])\nexcept RateLimitError as e:\n    print(f\"\u041f\u0440\u0435\u0432\u044b\u0448\u0435\u043d \u043b\u0438\u043c\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432: {e}\")\n    print(f\"\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437: {e.retry_after} \u0441\u0435\u043a\u0443\u043d\u0434\")\nexcept AuthenticationError as e:\n    print(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438: {e}\")\nexcept ValidationError as e:\n    print(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438: {e}\")\n    for detail in e.context.get(\"error_details\", []):\n        print(f\"\u041f\u043e\u043b\u0435 {detail['field']}: {detail['message']}\")\nexcept KrakenError as e:\n    print(f\"\u041e\u0431\u0449\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 Kraken: {e}\")\n```\n\n## \u0423\u0442\u0438\u043b\u0438\u0442\u044b\n\n### \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043c\u0435\u0434\u0438\u0430 \u0444\u0430\u0439\u043b\u0430\u043c\u0438\n\n```python\nfrom kraken_llm.utils.media import MediaUtils\n\n# \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043c\u0435\u0434\u0438\u0430 \u0444\u0430\u0439\u043b\u0430\nvalidation = MediaUtils.validate_media_file(\n    \"image.jpg\",\n    media_type=\"image\",\n    max_size=10 * 1024 * 1024\n)\n\n# \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\nresult = MediaUtils.resize_image(\n    \"large_image.jpg\",\n    \"resized_image.jpg\",\n    max_width=1024,\n    max_height=1024\n)\n\n# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 data URL\ndata_url = MediaUtils.create_data_url(\"image.jpg\")\n```\n\n## \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\n\n### \u0417\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432\n\n```bash\n# \u0412\u0441\u0435 \u0442\u0435\u0441\u0442\u044b\nmake test\n\n# \u0422\u043e\u043b\u044c\u043a\u043e unit \u0442\u0435\u0441\u0442\u044b\nmake test-unit\n\n# \u0422\u043e\u043b\u044c\u043a\u043e integration \u0442\u0435\u0441\u0442\u044b\nmake test-integration\n\n# \u0421 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435\u043c\nmake test-coverage\n```\n\n### \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439\n\n```python\nasync with create_universal_client() as client:\n    # \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439\n    test_results = await client.test_capabilities()\n    \n    for capability, result in test_results.items():\n        status = \"\u2705\" if result else \"\u274c\"\n        print(f\"{status} {capability}\")\n```\n\n## \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n\n\u0412 \u043f\u0430\u043f\u043a\u0435 `examples/` \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b:\n\n- `quick_universal_example.py` - \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442 \u0441 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c\n- `universal_client_example.py` - \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n- `complete_workflow_example.py` - \u041f\u043e\u043b\u043d\u044b\u0439 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\n- `adaptive_capabilities_example.py` - \u0410\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\n- `structured_output_fallback_example.py` - \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 \u0441 fallback\n- `reasoning_example.py` - \u0420\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438\n- `multimodal_example.py` - \u041c\u0443\u043b\u044c\u0442\u0438\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438\n- `streaming_example.py` - \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438\n- `function_tool_example.py` - \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b\n\n## \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430\n\n### \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\n\n```\nkraken_llm/\n\u251c\u2500\u2500 client/           # LLM \u043a\u043b\u0438\u0435\u043d\u0442\u044b\n\u2502   \u251c\u2500\u2500 base.py       # \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\u2502   \u251c\u2500\u2500 standard.py   # \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\u2502   \u251c\u2500\u2500 streaming.py  # \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\u2502   \u251c\u2500\u2500 structured.py # \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434\n\u2502   \u251c\u2500\u2500 reasoning.py  # \u0420\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438\n\u2502   \u251c\u2500\u2500 multimodal.py # \u041c\u0443\u043b\u044c\u0442\u0438\u043c\u043e\u0434\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\u2502   \u251c\u2500\u2500 adaptive.py   # \u0410\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\u2502   \u251c\u2500\u2500 asr.py        # \u0420\u0435\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438\n\u2502   \u251c\u2500\u2500 embeddings.py # \u0412\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\n\u2502   \u251c\u2500\u2500 universal.py  # \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\n\u2502   \u2514\u2500\u2500 factory.py    # \u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432\n\u251c\u2500\u2500 tools/            # \u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432\n\u251c\u2500\u2500 streaming/        # \u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438\n\u251c\u2500\u2500 structured/       # \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434\n\u251c\u2500\u2500 utils/           # \u0423\u0442\u0438\u043b\u0438\u0442\u044b (\u043c\u0435\u0434\u0438\u0430, \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435)\n\u251c\u2500\u2500 exceptions/       # \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a\n\u2514\u2500\u2500 models/          # \u041c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445\n```\n\n### \u041f\u0440\u0438\u043d\u0446\u0438\u043f\u044b \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\n\n1. **\u041c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0441\u0442\u044c**: \u041a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438\u043c\u0435\u0435\u0442 \u0447\u0435\u0442\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c\n2. **\u0420\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c**: \u041b\u0435\u0433\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0442\u0438\u043f\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\n3. **\u0422\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c**: \u041f\u043e\u043b\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 type hints \u0432\u043e \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445\n4. **\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c**: \u0412\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u043d\u0430 async/await\n5. **\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c**: \u0413\u0438\u0431\u043a\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0447\u0435\u0440\u0435\u0437 Pydantic Settings\n6. **\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a**: \u0418\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0441 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c\n7. **\u0410\u0432\u0442\u043e\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435**: \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 \u0444\u0430\u0431\u0440\u0438\u043a\u0443\n\n## \u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f\n\nMIT License - \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 ;-). \u0421\u043c. \u0444\u0430\u0439\u043b [LICENSE](LICENSE) \u0434\u043b\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0435\u0439.\n\n## \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430\n\n- \u041f\u0440\u0438\u043c\u0435\u0440\u044b: [examples/](examples/)\n- \u0422\u0435\u0441\u0442\u044b: [tests/](tests/)",
    "bugtrack_url": null,
    "license": null,
    "summary": "Universal LLM framework with full OpenAI API support",
    "version": "0.1.1.post1",
    "project_urls": {
        "Homepage": "https://github.com/antonshalin76/kraken_llm",
        "Issues": "https://github.com/antonshalin76/kraken_llm/issues",
        "Repository": "https://github.com/antonshalin76/kraken_llm"
    },
    "split_keywords": [
        "ai",
        " async",
        " llm",
        " machine-learning",
        " openai",
        " streaming"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "bfd72433ae55b3deec3d8c48319118ef3d11a298dc18beeb8bba4b9050bd9959",
                "md5": "113de7be3322c78a20aa44c8985545ab",
                "sha256": "e216a1a09e43f4fccb250cec831b165278b28131d552e78fcb2bac542e75aacf"
            },
            "downloads": -1,
            "filename": "kraken_llm-0.1.1.post1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "113de7be3322c78a20aa44c8985545ab",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 160201,
            "upload_time": "2025-09-14T19:32:50",
            "upload_time_iso_8601": "2025-09-14T19:32:50.241650Z",
            "url": "https://files.pythonhosted.org/packages/bf/d7/2433ae55b3deec3d8c48319118ef3d11a298dc18beeb8bba4b9050bd9959/kraken_llm-0.1.1.post1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d0e7298deff580ccebeee6f4772122058e3b6529947571de805fd88d84b00ec7",
                "md5": "907d05cb8727df45ba4394fd88ed4ed1",
                "sha256": "83240b1749aac43a750b19e376217ad16c54c8473d5cf53b13ad33cffe07d878"
            },
            "downloads": -1,
            "filename": "kraken_llm-0.1.1.post1.tar.gz",
            "has_sig": false,
            "md5_digest": "907d05cb8727df45ba4394fd88ed4ed1",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 337356,
            "upload_time": "2025-09-14T19:32:51",
            "upload_time_iso_8601": "2025-09-14T19:32:51.568847Z",
            "url": "https://files.pythonhosted.org/packages/d0/e7/298deff580ccebeee6f4772122058e3b6529947571de805fd88d84b00ec7/kraken_llm-0.1.1.post1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-14 19:32:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "antonshalin76",
    "github_project": "kraken_llm",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "openai",
            "specs": []
        },
        {
            "name": "outlines",
            "specs": []
        },
        {
            "name": "pydantic",
            "specs": []
        },
        {
            "name": "pydantic-settings",
            "specs": []
        },
        {
            "name": "httpx",
            "specs": []
        },
        {
            "name": "Pillow",
            "specs": []
        },
        {
            "name": "numpy",
            "specs": []
        },
        {
            "name": "python-dotenv",
            "specs": []
        },
        {
            "name": "typing-extensions",
            "specs": []
        }
    ],
    "lcname": "kraken-llm"
}
        
Elapsed time: 1.77727s