Повторный экзамен: Structured output — Union событий API: README.md
This commit is contained in:
@@ -1,3 +1,143 @@
|
||||
# task-6a1d75e5-povtornyy-ekzamen-structu
|
||||
# Structured Output – Union событий API
|
||||
|
||||
Решения домашних заданий
|
||||
## 📖 Описание
|
||||
|
||||
`solution.py` – практическое задание, в котором из **сырого лога** (несколько строк разного формата) извлекаются типизированные события через **Pydantic v2** и **LangChain ≥1.0**.
|
||||
Задача закрепляет работу с **Union + Enums + StructuredOutput**: одна входная лента, разные схемы, явный `type`/`kind` для маршрутизации.
|
||||
|
||||
> **Цель** – получить список типизированных событий `ApiEvent` из произвольного текста, а затем вывести их в табличном виде.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Установка зависимостей
|
||||
|
||||
```bash
|
||||
# Создайте и активируйте виртуальное окружение (необязательно)
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||
|
||||
# Установите зависимости
|
||||
pip install langchain-core langchain-openai pydantic python-dotenv
|
||||
```
|
||||
|
||||
> **Важно**:
|
||||
> * `langchain-openai` – подключает OpenAI API.
|
||||
> * Для работы с другими LLM (например, Ollama) замените `langchain-openai` на `langchain-ollama` и поправьте импорт в `solution.py`.
|
||||
> * В файле `.env` укажите переменную `OPENAI_API_KEY` (или `OLLAMA_BASE_URL` для Ollama).
|
||||
|
||||
---
|
||||
|
||||
## 🏃♂️ Запуск
|
||||
|
||||
### 1. Запуск по умолчанию (пример лога)
|
||||
|
||||
```bash
|
||||
python solution.py
|
||||
```
|
||||
|
||||
> Вы увидите вывод, где каждая строка лога преобразована в объект `ApiEvent` и напечатана в виде таблицы:
|
||||
|
||||
```
|
||||
Вход: 3 строки лога разного формата
|
||||
|
||||
Выход:
|
||||
┌───────┬───────────────────────┬────────┬───────────────┐
|
||||
│ kind │ path │ status │ duration_ms │
|
||||
├───────┼───────────────────────┼────────┼───────────────┤
|
||||
│ ok │ /api/v1/users │ 200 │ 123 │
|
||||
│ error │ /api/v1/orders │ 404 │ 0 │
|
||||
│ error │ /api/v1/payments │ 500 │ 0 │
|
||||
└───────┴───────────────────────┴────────┴───────────────┘
|
||||
```
|
||||
|
||||
### 2. Передача собственного текста
|
||||
|
||||
```bash
|
||||
python solution.py --text "GET /api/v1/products 200 45ms\nPOST /api/v1/cart 500 Internal Server Error"
|
||||
```
|
||||
|
||||
> Скрипт разбивает входной текст на строки, отправляет каждую в LLM, получает типизированный объект и выводит таблицу.
|
||||
|
||||
### 3. Использование собственного файла лога
|
||||
|
||||
```bash
|
||||
python solution.py --file path/to/your.log
|
||||
```
|
||||
|
||||
> Внутри `solution.py` реализована простая логика: если указан `--file`, то читается содержимое файла и используется в качестве входного текста.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Структура проекта
|
||||
|
||||
```
|
||||
.
|
||||
├── solution.py # Основной скрипт
|
||||
├── .env # Переменные окружения (OPENAI_API_KEY)
|
||||
└── README.md # Это файл
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Как это работает
|
||||
|
||||
1. **Модели**
|
||||
```python
|
||||
class HttpOkEvent(BaseModel):
|
||||
kind: Literal["ok"] = Field(..., description="Тип события: OK")
|
||||
status: Literal[200] = Field(..., description="HTTP статус 200")
|
||||
path: str = Field(..., description="Запрошенный путь")
|
||||
duration_ms: int = Field(..., description="Время выполнения в миллисекундах")
|
||||
|
||||
class HttpErrorEvent(BaseModel):
|
||||
kind: Literal["error"] = Field(..., description="Тип события: Ошибка")
|
||||
status: int = Field(..., description="HTTP статус 4xx/5xx")
|
||||
path: str = Field(..., description="Запрошенный путь")
|
||||
error_message: str = Field(..., description="Текст ошибки")
|
||||
```
|
||||
|
||||
2. **Union**
|
||||
```python
|
||||
ApiEvent = Annotated[
|
||||
Union[HttpOkEvent, HttpErrorEvent],
|
||||
Field(discriminator="kind")
|
||||
]
|
||||
```
|
||||
|
||||
3. **Парсинг**
|
||||
* Для каждой строки лога создаётся промпт, который задаёт задачу LLM: «Преобразуй строку в JSON, соответствующий `ApiEvent`».
|
||||
* Используется `PydanticOutputParser` (или `with_structured_output`) для строгой валидации.
|
||||
|
||||
4. **Вывод**
|
||||
* Список `ApiEvent` сериализуется через `model_dump()` и печатается в табличном формате (можно заменить на `tabulate` или `pandas`).
|
||||
|
||||
---
|
||||
|
||||
## 📌 Пример использования в коде
|
||||
|
||||
```python
|
||||
from solution import parse_log, print_events
|
||||
|
||||
log_text = """
|
||||
GET /api/v1/users 200 123ms
|
||||
POST /api/v1/orders 404 Not Found
|
||||
GET /api/v1/payments 500 Internal Server Error
|
||||
"""
|
||||
|
||||
events = parse_log(log_text)
|
||||
print_events(events)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Вклад
|
||||
|
||||
Если хотите улучшить скрипт (добавить поддержку новых форматов, улучшить промпт, добавить кэширование), создайте Pull Request. Убедитесь, что все тесты (если есть) проходят.
|
||||
|
||||
---
|
||||
|
||||
## 📄 Лицензия
|
||||
|
||||
MIT © 2026
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user