# Chunk Metadata Adapter
Библиотека для создания, управления и преобразования метаданных для чанков контента в различных системах, включая RAG-пайплайны, обработку документов и наборы данных для машинного обучения.
## Возможности
- Создание структурированных метаданных для чанков контента
- Поддержка разных форматов метаданных (плоский и структурированный)
- Отслеживание происхождения и жизненного цикла данных
- Сохранение информации о качестве и использовании чанков
- Поддержка расширенных метрик качества: coverage, cohesion, boundary_prev, boundary_next
## Жизненный цикл данных
Библиотека поддерживает следующие этапы жизненного цикла данных:
1. **RAW (Сырые данные)** - данные в исходном виде, сразу после загрузки в систему
2. **CLEANED (Очищенные)** - данные прошли предварительную очистку от шума, ошибок и опечаток
3. **VERIFIED (Проверенные)** - данные проверены на соответствие правилам и стандартам
4. **VALIDATED (Валидированные)** - данные прошли валидацию с учетом контекста и перекрестных ссылок
5. **RELIABLE (Надежные)** - данные признаны надежными и готовы к использованию в критических системах

### Преимущества учета жизненного цикла
- **Прозрачность происхождения** - отслеживание всех этапов обработки данных
- **Контроль качества** - возможность отфильтровать данные, не достигшие требуемых этапов обработки
- **Аудит процессов** - возможность анализировать и улучшать процессы очистки и валидации
- **Управление надежностью** - возможность использовать только проверенные данные для критических задач
## Установка
```bash
pip install chunk-metadata-adapter
```
## Использование
### Создание метаданных для чанка в процессе жизненного цикла
```python
from chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkStatus
import uuid
# Создаем builder для проекта
builder = ChunkMetadataBuilder(project="MyProject")
source_id = str(uuid.uuid4())
# Шаг 1: Создание чанка с сырыми данными (RAW)
raw_chunk = builder.build_semantic_chunk(
text="Данные пользователя: Иван Иванов, ivan@eample.com, Москва",
language="text",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
status=ChunkStatus.RAW, # Указываем статус RAW
body="Данные пользователя: Иван Иванов, ivan@eample.com, Москва" # raw
)
# Шаг 2: Очистка данных (исправление ошибок, опечаток)
cleaned_chunk = builder.build_semantic_chunk(
text="Данные пользователя: Иван Иванов, ivan@example.com, Москва", # Исправлена опечатка в email
language="text",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
status=ChunkStatus.CLEANED, # Данные очищены
body="Данные пользователя: Иван Иванов, ivan@example.com, Москва" # cleaned
)
# Шаг 3: Верификация данных (проверка по правилам)
verified_chunk = builder.build_semantic_chunk(
text="Данные пользователя: Иван Иванов, ivan@example.com, Москва",
language="text",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
status=ChunkStatus.VERIFIED, # Данные проверены
tags=["verified_email"], # Метки верификации
body="Данные пользователя: Иван Иванов, ivan@example.com, Москва" # raw
)
# Шаг 4: Валидация данных (проверка относительно других данных)
validated_chunk = builder.build_semantic_chunk(
text="Данные пользователя: Иван Иванов, ivan@example.com, Москва",
language="text",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
status=ChunkStatus.VALIDATED, # Данные валидированы
links=[f"reference:{str(uuid.uuid4())}"], # Связь с проверочным источником
body="Данные пользователя: Иван Иванов, ivan@example.com, Москва" # raw
)
# Шаг 5: Надежные данные (готовы к использованию)
reliable_chunk = builder.build_semantic_chunk(
text="Данные пользователя: Иван Иванов, ivan@example.com, Москва",
language="text",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
status=ChunkStatus.RELIABLE, # Данные признаны надежными
coverage=0.95,
cohesion=0.8,
boundary_prev=0.7,
boundary_next=0.9,
body="Данные пользователя: Иван Иванов, ivan@example.com, Москва" # raw
)
```
### Фильтрация чанков по статусу жизненного цикла
```python
# Пример функции для фильтрации чанков по статусу
def filter_chunks_by_status(chunks, min_status):
"""
Фильтрует чанки, оставляя только те, которые достигли определенного статуса
или выше в жизненном цикле данных.
Порядок статусов:
RAW < CLEANED < VERIFIED < VALIDATED < RELIABLE
Args:
chunks: список чанков для фильтрации
min_status: минимальный требуемый статус (ChunkStatus)
Returns:
отфильтрованный список чанков
"""
status_order = {
ChunkStatus.RAW.value: 1,
ChunkStatus.CLEANED.value: 2,
ChunkStatus.VERIFIED.value: 3,
ChunkStatus.VALIDATED.value: 4,
ChunkStatus.RELIABLE.value: 5
}
min_level = status_order.get(min_status.value, 0)
return [
chunk for chunk in chunks
if status_order.get(chunk.status.value, 0) >= min_level
]
# Пример использования
reliable_only = filter_chunks_by_status(all_chunks, ChunkStatus.RELIABLE)
```
## Best Practice: Рекомендованные сценарии использования
### 1. Создание чанка с расширенными метриками качества
```python
from chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkStatus
import uuid
builder = ChunkMetadataBuilder(project="MetricsDemo", unit_id="metrics-unit")
source_id = str(uuid.uuid4())
chunk = builder.build_semantic_chunk(
text="Sample text for metrics.",
language="text",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
status=ChunkStatus.RELIABLE,
coverage=0.95,
cohesion=0.8,
boundary_prev=0.7,
boundary_next=0.9,
body="Sample text for metrics." # raw
)
print(chunk.metrics)
```
### 2. Конвертация между flat и structured форматами
```python
from chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkRole
import uuid
builder = ChunkMetadataBuilder(project="ConversionExample")
structured_chunk = builder.build_semantic_chunk(
text="This is a sample chunk for conversion demonstration.",
language="text",
type=ChunkType.COMMENT,
source_id=str(uuid.uuid4()),
role=ChunkRole.REVIEWER,
body="This is a sample chunk for conversion demonstration." # raw
)
flat_dict = builder.semantic_to_flat(structured_chunk)
restored_chunk = builder.flat_to_semantic(flat_dict)
assert restored_chunk.uuid == structured_chunk.uuid
```
### 3. Цепочка обработки документа с обновлением статусов и метрик
```python
from chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkStatus
import uuid
builder = ChunkMetadataBuilder(project="ChainExample", unit_id="processor")
source_id = str(uuid.uuid4())
chunks = []
for i, text in enumerate([
"# Document Title",
"## Section 1\n\nThis is the content of section 1.",
"## Section 2\n\nThis is the content of section 2.",
"## Conclusion\n\nFinal thoughts on the topic."
]):
chunk = builder.build_semantic_chunk(
text=text,
language="markdown",
type=ChunkType.DOC_BLOCK,
source_id=source_id,
ordinal=i,
summary=f"Section {i}" if i > 0 else "Title",
body=text # raw
)
chunks.append(chunk)
# Устанавливаем связи и статусы
for i in range(1, len(chunks)):
chunks[i].links.append(f"parent:{chunks[0].uuid}")
chunks[i].status = ChunkStatus.INDEXED
# Обновляем метрики
for chunk in chunks:
chunk.metrics.quality_score = 0.95
chunk.metrics.used_in_generation = True
chunk.metrics.matches = 3
chunk.metrics.feedback.accepted = 2
```
### 4. Round-trip: flat -> structured -> flat
```python
from chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType
import uuid
builder = ChunkMetadataBuilder(project="RoundTripDemo")
source_id = str(uuid.uuid4())
flat = builder.build_flat_metadata(
text="Round-trip test chunk.",
source_id=source_id,
ordinal=1,
type=ChunkType.DOC_BLOCK,
language="text",
body="Round-trip test chunk." # raw
)
structured = builder.flat_to_semantic(flat)
flat2 = builder.semantic_to_flat(structured)
assert flat2["uuid"] == flat["uuid"]
```
## Business fields (Бизнес-поля)
Дополнительные поля для бизнес-логики:
| Поле | Тип | Описание |
|-----------|---------------|-----------------------------------------------------------------|
| category | Optional[str] | Бизнес-категория записи (например, 'наука', 'программирование') |
| title | Optional[str] | Заголовок или краткое название записи |
| year | Optional[int] | Год, связанный с записью (например, публикации) |
| is_public | Optional[bool]| Публичность записи (True/False) |
| source | Optional[str] | Источник данных ('user', 'external', 'import') |
### Пример использования (структурная модель)
```python
from chunk_metadata_adapter import SemanticChunk
chunk = SemanticChunk(
uuid="...",
type="DocBlock",
text="...",
language="ru",
sha256="...",
start=0,
end=10,
category="наука",
title="Краткое описание",
year=2024,
is_public=True,
source="user",
tags=["example", "science"]
)
```
### Пример использования (плоская модель)
```python
from chunk_metadata_adapter import FlatSemanticChunk
chunk = FlatSemanticChunk(
uuid="...",
type="DocBlock",
text="...",
language="ru",
sha256="...",
start=0,
end=10,
category="наука",
title="Краткое описание",
year=2024,
is_public=True,
source="user",
tags="example,science"
)
```
## Документация
Более подробную документацию можно найти в [директории docs](./docs).
## Лицензия
MIT
## to_flat_dict: flat dict для Redis
Функция `to_flat_dict` (и метод модели) возвращает плоский словарь, полностью готовый для записи в Redis:
- Все значения — только str/int/float (bool → "true"/"false", None → "", Enum → str, list/dict → JSON, datetime → ISO8601).
- Вложенные структуры превращаются в плоские ключи (`a.b.c`).
- created_at всегда присутствует и автозаполняется, если не указан (только на верхнем уровне).
- Все ключи — строки.
- Параметр `for_redis` по умолчанию True (поведение для Redis). Если False — старое поведение (часть значений остаётся в исходном типе).
- Внутренний параметр `first_call` (True только при первом вызове) гарантирует, что created_at добавляется только на верхнем уровне.
**Пример:**
```python
flat = chunk.to_flat_dict() # flat dict для Redis
# {'uuid': '...', 'is_public': 'false', 'embedding': '[0.1, 0.2]', 'block_meta.author': 'vasily', 'created_at': '2024-06-13T12:00:00+00:00', ...}
```
**Round-trip:**
- dict → to_flat_dict() → from_flat_dict() → dict — все типы и вложенность сохраняются, created_at только на верхнем уровне.
**Важно:**
- created_at — только на верхнем уровне, во вложенных dict (например, block_meta) отсутствует.
- Для seamless-интеграции с Redis не требуется ручная фильтрация или преобразование типов.
Raw data
{
"_id": null,
"home_page": null,
"name": "chunk-metadata-adapter",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": null,
"author": "Vasiliy zdanovskiy vasilyvz@gmail.com",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/10/a5/df3898db512d87f2787ffeb8babb21242ab5c9659a2f97679888a247424b/chunk_metadata_adapter-2.4.0.tar.gz",
"platform": null,
"description": "# Chunk Metadata Adapter\n\n\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0447\u0430\u043d\u043a\u043e\u0432 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f RAG-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u044b, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u043d\u0430\u0431\u043e\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f.\n\n## \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\n\n- \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0447\u0430\u043d\u043a\u043e\u0432 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430\n- \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 (\u043f\u043b\u043e\u0441\u043a\u0438\u0439 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439)\n- \u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0438 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0434\u0430\u043d\u043d\u044b\u0445\n- \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0447\u0430\u043d\u043a\u043e\u0432\n- \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430: coverage, cohesion, boundary_prev, boundary_next\n\n## \u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0434\u0430\u043d\u043d\u044b\u0445\n\n\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0430\u043f\u044b \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0434\u0430\u043d\u043d\u044b\u0445:\n\n1. **RAW (\u0421\u044b\u0440\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435)** - \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u0432\u0438\u0434\u0435, \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443\n2. **CLEANED (\u041e\u0447\u0438\u0449\u0435\u043d\u043d\u044b\u0435)** - \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0448\u043b\u0438 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043e\u0447\u0438\u0441\u0442\u043a\u0443 \u043e\u0442 \u0448\u0443\u043c\u0430, \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043e\u043a\n3. **VERIFIED (\u041f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u0435)** - \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u044b \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c \u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430\u043c\n4. **VALIDATED (\u0412\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435)** - \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0448\u043b\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u043f\u0435\u0440\u0435\u043a\u0440\u0435\u0441\u0442\u043d\u044b\u0445 \u0441\u0441\u044b\u043b\u043e\u043a\n5. **RELIABLE (\u041d\u0430\u0434\u0435\u0436\u043d\u044b\u0435)** - \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0437\u043d\u0430\u043d\u044b \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c\u0438 \u0438 \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0432 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445\n\n\n\n### \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0443\u0447\u0435\u0442\u0430 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430\n\n- **\u041f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f** - \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u044d\u0442\u0430\u043f\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445\n- **\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430** - \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0435 \u0434\u043e\u0441\u0442\u0438\u0433\u0448\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0445 \u044d\u0442\u0430\u043f\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\n- **\u0410\u0443\u0434\u0438\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432** - \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0443\u043b\u0443\u0447\u0448\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438\n- **\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c\u044e** - \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0437\u0430\u0434\u0430\u0447\n\n## \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n\n```bash\npip install chunk-metadata-adapter\n```\n\n## \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\n\n### \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0447\u0430\u043d\u043a\u0430 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430\n\n```python\nfrom chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkStatus\nimport uuid\n\n# \u0421\u043e\u0437\u0434\u0430\u0435\u043c builder \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430\nbuilder = ChunkMetadataBuilder(project=\"MyProject\")\nsource_id = str(uuid.uuid4())\n\n# \u0428\u0430\u0433 1: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0447\u0430\u043d\u043a\u0430 \u0441 \u0441\u044b\u0440\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 (RAW)\nraw_chunk = builder.build_semantic_chunk(\n text=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@eample.com, \u041c\u043e\u0441\u043a\u0432\u0430\",\n language=\"text\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n status=ChunkStatus.RAW, # \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 RAW\n body=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@eample.com, \u041c\u043e\u0441\u043a\u0432\u0430\" # raw\n)\n\n# \u0428\u0430\u0433 2: \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043e\u043a, \u043e\u043f\u0435\u0447\u0430\u0442\u043e\u043a)\ncleaned_chunk = builder.build_semantic_chunk(\n text=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\", # \u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0430 \u0432 email\n language=\"text\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n status=ChunkStatus.CLEANED, # \u0414\u0430\u043d\u043d\u044b\u0435 \u043e\u0447\u0438\u0449\u0435\u043d\u044b\n body=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\" # cleaned\n)\n\n# \u0428\u0430\u0433 3: \u0412\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c)\nverified_chunk = builder.build_semantic_chunk(\n text=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\",\n language=\"text\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n status=ChunkStatus.VERIFIED, # \u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u044b\n tags=[\"verified_email\"], # \u041c\u0435\u0442\u043a\u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438\n body=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\" # raw\n)\n\n# \u0428\u0430\u0433 4: \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445)\nvalidated_chunk = builder.build_semantic_chunk(\n text=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\",\n language=\"text\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n status=ChunkStatus.VALIDATED, # \u0414\u0430\u043d\u043d\u044b\u0435 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u044b\n links=[f\"reference:{str(uuid.uuid4())}\"], # \u0421\u0432\u044f\u0437\u044c \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c\n body=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\" # raw\n)\n\n# \u0428\u0430\u0433 5: \u041d\u0430\u0434\u0435\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 (\u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e)\nreliable_chunk = builder.build_semantic_chunk(\n text=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\",\n language=\"text\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n status=ChunkStatus.RELIABLE, # \u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0437\u043d\u0430\u043d\u044b \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c\u0438\n coverage=0.95,\n cohesion=0.8,\n boundary_prev=0.7,\n boundary_next=0.9,\n body=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432, ivan@example.com, \u041c\u043e\u0441\u043a\u0432\u0430\" # raw\n)\n```\n\n### \u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f \u0447\u0430\u043d\u043a\u043e\u0432 \u043f\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0443 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430\n\n```python\n# \u041f\u0440\u0438\u043c\u0435\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0447\u0430\u043d\u043a\u043e\u0432 \u043f\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0443\ndef filter_chunks_by_status(chunks, min_status):\n \"\"\"\n \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u0442 \u0447\u0430\u043d\u043a\u0438, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430\n \u0438\u043b\u0438 \u0432\u044b\u0448\u0435 \u0432 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.\n \n \u041f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432: \n RAW < CLEANED < VERIFIED < VALIDATED < RELIABLE\n \n Args:\n chunks: \u0441\u043f\u0438\u0441\u043e\u043a \u0447\u0430\u043d\u043a\u043e\u0432 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438\n min_status: \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 (ChunkStatus)\n \n Returns:\n \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0447\u0430\u043d\u043a\u043e\u0432\n \"\"\"\n status_order = {\n ChunkStatus.RAW.value: 1,\n ChunkStatus.CLEANED.value: 2,\n ChunkStatus.VERIFIED.value: 3,\n ChunkStatus.VALIDATED.value: 4, \n ChunkStatus.RELIABLE.value: 5\n }\n \n min_level = status_order.get(min_status.value, 0)\n \n return [\n chunk for chunk in chunks \n if status_order.get(chunk.status.value, 0) >= min_level\n ]\n\n# \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\nreliable_only = filter_chunks_by_status(all_chunks, ChunkStatus.RELIABLE)\n```\n\n## Best Practice: \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n\n### 1. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0447\u0430\u043d\u043a\u0430 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u0440\u0438\u043a\u0430\u043c\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430\n\n```python\nfrom chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkStatus\nimport uuid\n\nbuilder = ChunkMetadataBuilder(project=\"MetricsDemo\", unit_id=\"metrics-unit\")\nsource_id = str(uuid.uuid4())\nchunk = builder.build_semantic_chunk(\n text=\"Sample text for metrics.\",\n language=\"text\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n status=ChunkStatus.RELIABLE,\n coverage=0.95,\n cohesion=0.8,\n boundary_prev=0.7,\n boundary_next=0.9,\n body=\"Sample text for metrics.\" # raw\n)\nprint(chunk.metrics)\n```\n\n### 2. \u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 flat \u0438 structured \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u043c\u0438\n\n```python\nfrom chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkRole\nimport uuid\n\nbuilder = ChunkMetadataBuilder(project=\"ConversionExample\")\nstructured_chunk = builder.build_semantic_chunk(\n text=\"This is a sample chunk for conversion demonstration.\",\n language=\"text\",\n type=ChunkType.COMMENT,\n source_id=str(uuid.uuid4()),\n role=ChunkRole.REVIEWER,\n body=\"This is a sample chunk for conversion demonstration.\" # raw\n)\nflat_dict = builder.semantic_to_flat(structured_chunk)\nrestored_chunk = builder.flat_to_semantic(flat_dict)\nassert restored_chunk.uuid == structured_chunk.uuid\n```\n\n### 3. \u0426\u0435\u043f\u043e\u0447\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0441 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432 \u0438 \u043c\u0435\u0442\u0440\u0438\u043a\n\n```python\nfrom chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType, ChunkStatus\nimport uuid\n\nbuilder = ChunkMetadataBuilder(project=\"ChainExample\", unit_id=\"processor\")\nsource_id = str(uuid.uuid4())\nchunks = []\nfor i, text in enumerate([\n \"# Document Title\",\n \"## Section 1\\n\\nThis is the content of section 1.\",\n \"## Section 2\\n\\nThis is the content of section 2.\",\n \"## Conclusion\\n\\nFinal thoughts on the topic.\"\n]):\n chunk = builder.build_semantic_chunk(\n text=text,\n language=\"markdown\",\n type=ChunkType.DOC_BLOCK,\n source_id=source_id,\n ordinal=i,\n summary=f\"Section {i}\" if i > 0 else \"Title\",\n body=text # raw\n )\n chunks.append(chunk)\n# \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0432\u044f\u0437\u0438 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u044b\nfor i in range(1, len(chunks)):\n chunks[i].links.append(f\"parent:{chunks[0].uuid}\")\n chunks[i].status = ChunkStatus.INDEXED\n# \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043c\u0435\u0442\u0440\u0438\u043a\u0438\nfor chunk in chunks:\n chunk.metrics.quality_score = 0.95\n chunk.metrics.used_in_generation = True\n chunk.metrics.matches = 3\n chunk.metrics.feedback.accepted = 2\n```\n\n### 4. Round-trip: flat -> structured -> flat\n\n```python\nfrom chunk_metadata_adapter import ChunkMetadataBuilder, ChunkType\nimport uuid\n\nbuilder = ChunkMetadataBuilder(project=\"RoundTripDemo\")\nsource_id = str(uuid.uuid4())\nflat = builder.build_flat_metadata(\n text=\"Round-trip test chunk.\",\n source_id=source_id,\n ordinal=1,\n type=ChunkType.DOC_BLOCK,\n language=\"text\",\n body=\"Round-trip test chunk.\" # raw\n)\nstructured = builder.flat_to_semantic(flat)\nflat2 = builder.semantic_to_flat(structured)\nassert flat2[\"uuid\"] == flat[\"uuid\"]\n```\n\n## Business fields (\u0411\u0438\u0437\u043d\u0435\u0441-\u043f\u043e\u043b\u044f)\n\n\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438:\n\n| \u041f\u043e\u043b\u0435 | \u0422\u0438\u043f | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 |\n|-----------|---------------|-----------------------------------------------------------------|\n| category | Optional[str] | \u0411\u0438\u0437\u043d\u0435\u0441-\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, '\u043d\u0430\u0443\u043a\u0430', '\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435') |\n| title | Optional[str] | \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438\u043b\u0438 \u043a\u0440\u0430\u0442\u043a\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 |\n| year | Optional[int] | \u0413\u043e\u0434, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u0437\u0430\u043f\u0438\u0441\u044c\u044e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438) |\n| is_public | Optional[bool]| \u041f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438 (True/False) |\n| source | Optional[str] | \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 ('user', 'external', 'import') |\n\n### \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f (\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c)\n\n```python\nfrom chunk_metadata_adapter import SemanticChunk\nchunk = SemanticChunk(\n uuid=\"...\",\n type=\"DocBlock\",\n text=\"...\",\n language=\"ru\",\n sha256=\"...\",\n start=0,\n end=10,\n category=\"\u043d\u0430\u0443\u043a\u0430\",\n title=\"\u041a\u0440\u0430\u0442\u043a\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\",\n year=2024,\n is_public=True,\n source=\"user\",\n tags=[\"example\", \"science\"]\n)\n```\n\n### \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f (\u043f\u043b\u043e\u0441\u043a\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c)\n\n```python\nfrom chunk_metadata_adapter import FlatSemanticChunk\nchunk = FlatSemanticChunk(\n uuid=\"...\",\n type=\"DocBlock\",\n text=\"...\",\n language=\"ru\",\n sha256=\"...\",\n start=0,\n end=10,\n category=\"\u043d\u0430\u0443\u043a\u0430\",\n title=\"\u041a\u0440\u0430\u0442\u043a\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\",\n year=2024,\n is_public=True,\n source=\"user\",\n tags=\"example,science\"\n)\n```\n\n## \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\n\n\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 [\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 docs](./docs).\n\n## \u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f\n\nMIT \n\n## to_flat_dict: flat dict \u0434\u043b\u044f Redis\n\n\u0424\u0443\u043d\u043a\u0446\u0438\u044f `to_flat_dict` (\u0438 \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0434\u0435\u043b\u0438) \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043b\u043e\u0441\u043a\u0438\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 Redis:\n- \u0412\u0441\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u0442\u043e\u043b\u044c\u043a\u043e str/int/float (bool \u2192 \"true\"/\"false\", None \u2192 \"\", Enum \u2192 str, list/dict \u2192 JSON, datetime \u2192 ISO8601).\n- \u0412\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u043f\u043b\u043e\u0441\u043a\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 (`a.b.c`).\n- created_at \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438 \u0430\u0432\u0442\u043e\u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d (\u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435).\n- \u0412\u0441\u0435 \u043a\u043b\u044e\u0447\u0438 \u2014 \u0441\u0442\u0440\u043e\u043a\u0438.\n- \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 `for_redis` \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e True (\u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Redis). \u0415\u0441\u043b\u0438 False \u2014 \u0441\u0442\u0430\u0440\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 (\u0447\u0430\u0441\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u0442\u0438\u043f\u0435).\n- \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 `first_call` (True \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435) \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e created_at \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435.\n\n**\u041f\u0440\u0438\u043c\u0435\u0440:**\n```python\nflat = chunk.to_flat_dict() # flat dict \u0434\u043b\u044f Redis\n# {'uuid': '...', 'is_public': 'false', 'embedding': '[0.1, 0.2]', 'block_meta.author': 'vasily', 'created_at': '2024-06-13T12:00:00+00:00', ...}\n```\n\n**Round-trip:**\n- dict \u2192 to_flat_dict() \u2192 from_flat_dict() \u2192 dict \u2014 \u0432\u0441\u0435 \u0442\u0438\u043f\u044b \u0438 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f, created_at \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435.\n\n**\u0412\u0430\u0436\u043d\u043e:**\n- created_at \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435, \u0432\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 dict (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, block_meta) \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442.\n- \u0414\u043b\u044f seamless-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 Redis \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0440\u0443\u0447\u043d\u0430\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f \u0438\u043b\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u043e\u0432. \n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Reusable metadata builder for chunk-based systems",
"version": "2.4.0",
"project_urls": {
"Bug Tracker": "https://github.com/yourusername/chunk_metadata_adapter/issues",
"Homepage": "https://github.com/yourusername/chunk_metadata_adapter"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "84e31532b0a17bf19639feb6265f1b706cf3bae94c9b407031bc2ffa805a430f",
"md5": "0882c8cc9e4fa565b18d15825ee0f72a",
"sha256": "42404a1d626e26ce6888fa827b9aace3ef3d1e6c002a52a75cf9e10ca2b12f04"
},
"downloads": -1,
"filename": "chunk_metadata_adapter-2.4.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0882c8cc9e4fa565b18d15825ee0f72a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 51820,
"upload_time": "2025-07-16T20:28:28",
"upload_time_iso_8601": "2025-07-16T20:28:28.187604Z",
"url": "https://files.pythonhosted.org/packages/84/e3/1532b0a17bf19639feb6265f1b706cf3bae94c9b407031bc2ffa805a430f/chunk_metadata_adapter-2.4.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "10a5df3898db512d87f2787ffeb8babb21242ab5c9659a2f97679888a247424b",
"md5": "03bad209c3ca7dbcb231a49b11e2629b",
"sha256": "124de8e64f86c76924f71affe12e49c15f015c3716593b9ade8b0d0960746ff0"
},
"downloads": -1,
"filename": "chunk_metadata_adapter-2.4.0.tar.gz",
"has_sig": false,
"md5_digest": "03bad209c3ca7dbcb231a49b11e2629b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 100504,
"upload_time": "2025-07-16T20:28:30",
"upload_time_iso_8601": "2025-07-16T20:28:30.064356Z",
"url": "https://files.pythonhosted.org/packages/10/a5/df3898db512d87f2787ffeb8babb21242ab5c9659a2f97679888a247424b/chunk_metadata_adapter-2.4.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-16 20:28:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "yourusername",
"github_project": "chunk_metadata_adapter",
"github_not_found": true,
"lcname": "chunk-metadata-adapter"
}