scan, split, OCR, prepare for LLM
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

CODE_STYLE.md 3.6KB

Стиль кода

Язык

Python 3.12+


Типизация

Полная типизация обязательна.

Избегать использования Any.


Размер функций

Желательно не более 40 строк.

Максимум около 80 строк.

Если функция становится длиннее — разделить её.


Размер файлов

Желательно до 300 строк.

Максимум около 500 строк.


Именование

Использовать понятные имена.

Хорошо:

load_image()

split_grid()

rotate_image()

add_border()

Плохо:

proc()

run2()

tmp()


Глобальное состояние

Не использовать глобальные переменные.

Не использовать Singleton.


Магические числа

Все значения должны быть вынесены в именованные константы либо параметры функций.


Ошибки

Использовать исключения.

CLI должен завершаться ненулевым кодом возврата.

Сообщения должны быть понятны пользователю.


Логирование

Использовать logging.

Не использовать print() для отладки.


Качество

Следовать PEP8.

Использовать Ruff.

Не оставлять:

  • закомментированный код;
  • неиспользуемый код;
  • TODO без объяснения.

Паттерны, выработанные в проекте

Корректоры: мутация in-place

Функции-корректоры (LLM, VLM, fixups) изменяют ParsedBlock.content на месте и возвращают None.

def fix_ocr_errors(blocks: list[ParsedBlock]) -> None:  # ← None, не list
    for block in blocks:
        if block.label == "formula":
            block.content = _fix_formula_errors(block.content)

Протокол:

class Corrector(Protocol):
    def __call__(self, block: ParsedBlock) -> None: ...

Общие переменные окружения через src/env.py

Любой модуль, читающий .env, использует from src.env import load_env. Не дублировать _load_env() в каждом файле.

Multi-engine через фабрику

def _get_ocr_engine(name: str):
    if name == "surya":
        return surya_ocr_image, surya_ocr_batch, "Surya 2 VLM"
    return ocr_image, None, "PP-StructureV3"

Возвращает (single_fn, batch_fn, display_name). Новый движок — добавить elif-ветку.

Синглтоны для ML-моделей

Допустимы ленивые синглтоны для тяжёлых объектов (модели, pipeline’ы), но через фабричную функцию:

_engine: OcrEngine | None = None

def ocr_image(path: str) -> OcrPageResult:
    global _engine
    if _engine is None:
        _engine = OcrEngine()
    return _engine.process(path)

Не использовать модульные глобальные переменные напрямую.

Периодический SOLID/DRY/KISS/YAGNI аудит

После реализации крупной фичи — прогнать аудит по .ai/SOLID_AUDIT.md. Не накапливать технический долг.