Skip to main content

Asynchronous facade for PostgreSQL and MinIO for corporate semantic search systems.

Project description

SensoryDataClient: Асинхронный клиент для данных и их структуры

CI Status Coverage License: MIT

SensoryDataClient — это изолированный, портируемый Python-модуль, предоставляющий единый асинхронный интерфейс для работы с объектным хранилищем MinIO и реляционной базой данных PostgreSQL. Он спроектирован как надежный фундамент для сервисов, которым требуется атомарно управлять не только файлами и их метаданными, но и их структурированным содержимым в виде строк.

🎯 Миссия

Предоставить разработчикам production-ready инструмент, который инкапсулирует всю сложность взаимодействия с хранилищами данных, предлагая простой, типобезопасный и асинхронный API для управления как целыми документами, так и их составными частями.

✨ Ключевые возможности

  • Асинхронность "из коробки": Построен на asyncio, SQLAlchemy 2.0 (async), asyncpg и асинхронных обертках над SDK MinIO.
  • Единый фасад (DataClient): Один класс для управления файлами, их метаданными и структурированными строками. Больше не нужно жонглировать несколькими клиентами в бизнес-логике.
  • Управление строками документа (Document Lines): Возможность сохранять, обновлять и запрашивать разобранное содержимое документа (текст, код, ссылки на изображения) с указанием типа и точной позиции (float), что идеально подходит для реализации diff-обновлений и RAG-пайплайнов.
  • Атомарные операции: Метод upload_file гарантирует, что метаданные не появятся в БД без соответствующего файла в MinIO (с автоматическим откатом). Операции со строками также транзакционны.
  • Типобезопасность: Активное использование Pydantic для моделей данных и 100% покрытие кода тайп-хинтами.
  • Готовность к развертыванию: Настройка через переменные окружения, структурированное JSON-логирование и удобный CLI-интерфейс на базе Typer.
  • Простота для разработчика: Готовое Docker Compose окружение для локального тестирования и CLI для быстрой инициализации.

🏗️ Архитектура

Клиент реализует паттерн Фасад, скрывая детали работы с конкретными репозиториями. В отличие от предыдущей версии, работа с PostgreSQL теперь разделена на два репозитория для лучшего разделения ответственности (SRP).

┌────────────────────────────────┐
│   Ваш Сервис (Business Logic)  │
└───────────────┬────────────────┘
                │
┌───────────────▼────────────────┐
│         DataClient             │  <- Единая точка входа
└───────────────┬────────────────┘
      ┌─────────┴─────────┬────────────────┐
      │                   │                │
┌─────▼─────┐       ┌─────▼──────┐   ┌─────▼──────┐
│  MinIO    │       │ MetaData   │   │ Line       │
│ Repository│       │ Repository │   │ Repository │
└───────────┘       └────────────┘   └────────────┘
 (MinIO SDK)         (SQLAlchemy)     (SQLAlchemy)

🚀 Установка

Для использования клиента в других проектах предполагается его установка из приватного репозитория или локально.

Установка для разработки

Шаг 1: Клонируйте репозиторий

git clone https://github.com/sensoryfox/datafileclient.git
cd datafileclient

Шаг 2: Установите зависимости Эта команда установит все необходимые библиотеки для работы клиента и для его разработки (тесты, линтеры).

pip install -e ".[dev]"

Организация хранения таблиц с данными:

┌───────────────────┐       ┌───────────────────┐
│   StoredFileORM   │──────▶│    DocumentORM    │
│ (stored_files)    │ 1..1  │    (documents)    │
└───────────────────┘       └─────────┬─────────┘
                                      │ 1..N
                                      ▼
                          ┌───────────────────┐
                          │     RawLineORM    │  <- Главная "лента" контента
                          │    (raw_lines)    │
                          └─────────┬─────────┘
         ┌──────────────────────────┼──────────────────────────┐
         │ 1..0/1                   │ 1..0/1                   │ 1..0/1
         ▼                          ▼                          ▼
┌───────────────────┐    ┌───────────────────┐    ┌───────────────────┐
│  DocumentLineORM  │    │    ImageLineORM   │    │     AudioLineORM    │
│ (lines_document)  │    │    (lines_image)  │    │     (lines_audio)   │
└───────────────────┘    └───────────────────┘    └───────────────────┘
(геометрия, страница)  (путь в S3, alt-text)    (таймкоды, спикер)

🐳 Локальная разработка с Docker

Для разработки и тестирования клиента вам понадобятся запущенные экземпляры PostgreSQL и MinIO. Мы предоставляем готовую конфигурацию docker-compose.

Шаг 1: Создайте файл с переменными окружения Скопируйте пример. Для локального запуска менять ничего не нужно.

cp .env.example .env

Важно: Файл .env должен содержать POSTGRES_HOST=localhost и MINIO_ENDPOINT=localhost:9000 для подключения с вашего компьютера к контейнерам.

Шаг 2: Запустите окружение Эта команда поднимет контейнеры с PostgreSQL и MinIO.

docker-compose up -d

После запуска:

  • Веб-консоль MinIO будет доступна по адресу http://localhost:9001.
  • PostgreSQL будет доступен по адресу localhost:5432.

Шаг 3: Инициализируйте окружение Эта команда создаст таблицы в PostgreSQL (documents, document_lines) и бакет в MinIO.

python -m sensory_data_client init

Шаг 4: Проверьте соединения Убедитесь, что ваш локальный Python-код может достучаться до сервисов в Docker.

python -m sensory_data_client check

Вы должны увидеть:

 Connection Check
✔ PostgreSQL connection: OK
✔ MinIO connection: OK (bucket: 'test-bucket')

🛠️ Пример использования

import asyncio
from uuid import uuid4
from sensory_data_client import create_data_client, DocumentCreate, DocumentMetadata, Line

# --- 1. Инициализация клиента через фабрику ---
client = create_data_client()

# --- 2. Модель метаданных ---
doc_meta = DocumentCreate(
    user_document_id="ext-id-456",
    name="Project Proposal.md",
    owner="user-02",
    access_group="engineering",
    extension="md"
)

# --- 3. Контент файла ---
file_content = b"# Project Sensory\n\nThis is the main proposal document."

# --- 4. Структурированные строки из файла ---
document_lines = [
    Line(block_id="block-1", position=1.0, type="header", content="# Project Sensory"),
    Line(block_id="block-2", position=2.0, type="paragraph", content="This is the main proposal document."),
]


async def main():
    """Основной сценарий использования клиента."""
    new_doc_id = None
    try:
        # --- 5. Загрузка файла и метаданных ---
        print("Uploading file...")
        new_doc = await client.upload_file(
            file_name="proposal.md",
            content=file_content,
            meta=doc_meta
        )
        new_doc_id = new_doc.id
        print(f"Document created with ID: {new_doc_id}")

        # --- 6. Сохранение разобранных строк документа ---
        print("\nSaving document lines...")
        await client.save_document_lines(new_doc_id, document_lines)
        print(f"Saved {len(document_lines)} lines.")

        # --- 7. Получение строк документа из БД ---
        print("\nFetching document lines...")
        retrieved_lines = await client.list_doclines(new_doc_id)
        assert len(retrieved_lines) == len(document_lines)
        assert retrieved_lines[0].content == "# Project Sensory"
        print("Lines match!")

        # --- 8. Генерация временной ссылки на скачивание ---
        print("\nGenerating presigned URL for the original file...")
        download_url = await client.generate_download_url(new_doc_id, expires_in=60)
        print(f"URL (expires in 60s): {download_url}")

    except Exception as e:
        print(f"An error occurred: {e}")

    finally:
        # --- 9. Удаление документа для очистки ---
        if new_doc_id:
            print(f"\nDeleting document {new_doc_id}...")
            # Удаление метаданных и файла. Строки будут удалены каскадно или их нужно удалять отдельно.
            await client.delete_file(new_doc_id)
            print("Document deleted successfully.")

if __name__ == "__main__":
    asyncio.run(main())

⚙️ Конфигурация

Клиент настраивается через переменные окружения. Значения по умолчанию можно найти в файле .env.example.

Переменная Описание Значение по умолчанию
POSTGRES_HOST Хост PostgreSQL localhost
POSTGRES_PORT Порт PostgreSQL 5432
POSTGRES_DB Имя базы данных documents
POSTGRES_USER Пользователь PostgreSQL postgres
POSTGRES_PASSWORD Пароль пользователя PostgreSQL postgres
MINIO_ENDPOINT Адрес MinIO (хост:порт) localhost:9000
MINIO_ACCESS_KEY Ключ доступа MinIO minioadmin
MINIO_SECRET_KEY Секретный ключ MinIO minioadmin
MINIO_BUCKET Имя бакета для хранения файлов documents
MINIO_SECURE Использовать TLS для MinIO (True/False) False
LOG_LEVEL Уровень логирования (INFO, DEBUG, ...) INFO

⌨️ Command-Line Interface (CLI)

Для удобства разработки в клиент встроен CLI на базе Typer. Вызывается как модуль.

  • Инициализировать сервисы: Создает таблицы в БД и бакет в MinIO.
python -m sensory_data_client init
  • Проверить соединения: Проверяет доступность PostgreSQL и MinIO с текущими настройками.
python -m sensory_data_client check

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

Проект использует testcontainers для запуска интеграционных тестов в изолированном окружении с реальными версиями PostgreSQL и MinIO.

Для запуска всех тестов используйте pytest:

pytest

Тесты автоматически поднимут необходимые Docker-контейнеры, выполнят проверки и остановят их после завершения.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sensory_data_client-0.2.45.tar.gz (59.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sensory_data_client-0.2.45-py3-none-any.whl (79.8 kB view details)

Uploaded Python 3

File details

Details for the file sensory_data_client-0.2.45.tar.gz.

File metadata

  • Download URL: sensory_data_client-0.2.45.tar.gz
  • Upload date:
  • Size: 59.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.1

File hashes

Hashes for sensory_data_client-0.2.45.tar.gz
Algorithm Hash digest
SHA256 11427392a6852637d269a57ec1042849b8f4883ca11a038d9b348b77ccf721e8
MD5 99cecc49cb760db8db5ed0966d47c695
BLAKE2b-256 0b3acb1de9a0a9b45acdd14146dbede873f3cfb78ac7b4e4b7a48e46dff2ad7c

See more details on using hashes here.

File details

Details for the file sensory_data_client-0.2.45-py3-none-any.whl.

File metadata

File hashes

Hashes for sensory_data_client-0.2.45-py3-none-any.whl
Algorithm Hash digest
SHA256 6f704e72a4c731e321d4afecf1714ae37ba543daebbb62b53549a534ef38e7ea
MD5 cd847c2d2a538b2370a818507778f189
BLAKE2b-256 911291e910bd12c093d4c2f63d76fe1c9e90fcee0aab1cf5a6073778417ee1e5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page