Conversation
HadronCollider
left a comment
There was a problem hiding this comment.
Влейте сюда изменения по комментариям из #647
| while time.time() - start_time < self.max_wait_time: | ||
| task_result = AsyncResult(task_id) | ||
| if task_result.state == 'SUCCESS': | ||
| recognized_text = task_result.result | ||
| recognized_text = re.sub(r'\s+', ' ', recognized_text) | ||
| image.text = recognized_text | ||
| add_image_text(task_id, recognized_text) | ||
| return recognized_text.strip() | ||
| time.sleep(1) |
There was a problem hiding this comment.
кажется, подобный подход ожидания не самый лучший (мы по факту блокируем всю проверку / очередь) - можно ли сделать "заглушку" (по типу фидбека "проверяется" в этой проверке), а в celery-задаче с тессерактом после распознавания и обработки - обновлять данные в БД проверки? но стоит добавить какую-то проверку, не слишком ли долго тессеракт обрабатывает картинку или вообще её не выполнил (чтобы обновить фидбек/результат критерия в соответствии со сложившейся ситуацией)
| 'is_failed': False, | ||
| 'params_for_passback': current_user.params_for_passback | ||
| 'params_for_passback': current_user.params_for_passback, | ||
| 'tesseract_result': -1 |
There was a problem hiding this comment.
Чтобы не "обременять" модель проверки результатом тессеракта (он вероятно может быть большим и конкретно к проверке может не относиться - это больше характеристика файла) - вынесите в отдельную коллекцию - в неё же будет писать celery-задача и смотреть задачи по проверке - так же уйдут заполнения поля -1 и получением данных из бд на этапе формирования check
связь по check id
| } | ||
|
|
||
| @celery.task(name="tesseract_recognize", queue='tesseract-queue', bind=True, max_retries=MAX_RETRIES, soft_time_limit=TASK_SOFT_TIME_LIMIT) | ||
| def tesseract_recognize(self, check_id): |
There was a problem hiding this comment.
при подобном запуске теряется возможность устанавливать параметры из критерия - остаются только захардкоженые from main.checks.report_checks.image_text_check import SYMBOLS_SET, MAX_SYMBOLS_PERCENTAGE, MAX_TEXT_DENSITY
может быть можно запускать эту задачу из критерия, а не при извлечении изображений / загрузке файла, либо собирать только информацию по анализу изображений, а формировать полноценный фидбек в самом критерии?
(при втором варианте появляется зависимость от скорости работы тессеракта - "успеет ли он обработать изображения до начала проверки по критерию" плюс не совместим с текущим асинхронным подходом к обработке тессеракта -- поэтому насчет него не уверен)
| if self.laplacian_score < self.min_laplacian: | ||
| deny_list.append(f"Изображение с подписью '{img.caption}' имеет низкий показатель лапласиана: {self.laplacian_score} (минимум {self.min_laplacian}).<br>") | ||
|
|
||
| if self.entropy_score < self.min_entropy: | ||
| deny_list.append(f"Изображение с подписью '{img.caption}' имеет низкую энтропию: {self.entropy_score} (минимум {self.min_entropy}).<br>") |
HadronCollider
left a comment
There was a problem hiding this comment.
Пока оставил комментарии только по модели - остальной код по мере обновлений / необходимости
Одна из мыслей - расширить данные о файле (сейчас она почти не используется и поверхностная), добавив туда агрегированные данные по всем изображениям в нем ()
| is_failed = none_to_false(self.is_failed) # None for old checks => False, True->True, False->False | ||
| return {'is_ended': is_ended, 'is_failed': is_failed} | ||
|
|
||
| class Image(PackableWithId): |
There was a problem hiding this comment.
Мы планируем уйти от PackableWithId в сторону "нормальной" mongo document model (с указанием типов полей и прочего), поэтому предлагаю новые модели делать с помощью них (поддержав нужны операции)
| def __init__(self, dictionary=None): | ||
| super().__init__(dictionary) | ||
| dictionary = dictionary or {} | ||
| self.check_id = dictionary.get('check_id') # Привязка к check_id |
There was a problem hiding this comment.
Возможно тут стоит сохранять и id документа - 99% уверенности, что у него сейчас ID одинаковый с проверкой, но в будущем возможны изменения (и тогда документ будет, например, один, а проверок с ним несколько), сохранить изображения хватит один раз именно для документа
| dictionary = dictionary or {} | ||
| self.check_id = dictionary.get('check_id') # Привязка к check_id | ||
| self.caption = dictionary.get('caption', '') # Подпись к изображению | ||
| self.image_data = dictionary.get('image_data') # Файл изображения в формате bindata |
There was a problem hiding this comment.
Полезный момент на будущее - добавить checksum на случай дубликатов (чтобы одна одинаковая фотка в 100 отправок / отчетах нам не занимала лишнее место и ресурсы на обработку)
| self.caption = dictionary.get('caption', '') # Подпись к изображению | ||
| self.image_data = dictionary.get('image_data') # Файл изображения в формате bindata | ||
| self.image_size = dictionary.get('image_size') # Размер изображения в сантимерах | ||
| self.text = dictionary.get('text', None) |
There was a problem hiding this comment.
Возможно, обсуждали это ранее - есть мысли, что требующиеся нам метрики изображений (читаемость, плотность текста, пр) стоит сделать сразу при распознавании и хранить либо в документе изображения (как и сам полученный текст), либо в отдельной коллекции
| is_failed = none_to_false(self.is_failed) # None for old checks => False, True->True, False->False | ||
| return {'is_ended': is_ended, 'is_failed': is_failed} | ||
|
|
||
| class Image: |
There was a problem hiding this comment.
Напоминаю о том, что новые модели БД надо делать через https://pymodm.readthedocs.io/en/latest/api/#pymodm.MongoModel
| if "graphic" in run._element.xml: | ||
| image_streams = run._element.findall('.//a:blip', namespaces={ | ||
| 'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'}) | ||
| for image_stream in image_streams: | ||
| embed_id = image_stream.get( | ||
| '{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed') | ||
| if embed_id: | ||
| image_found = True | ||
| image_part = self.file.part.related_parts[embed_id] | ||
| image_data = image_part.blob | ||
| extent = run._element.find('.//wp:extent', namespaces={ | ||
| 'wp': 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'}) | ||
| width_cm = height_cm = None | ||
| if extent is not None: | ||
| width_cm = int(extent.get('cx')) / emu_to_cm | ||
| height_cm = int(extent.get('cy')) / emu_to_cm |
There was a problem hiding this comment.
Вынесите логику поиска в отдельную функцию (возвращающую нужный вам Namespace с полями) + строки-схемы в константы (хотя бы на уровне данного модуля), чтобы их было проще контролировать
| super().__init__(dictionary) | ||
| dictionary = dictionary or {} | ||
| self.filename = dictionary.get('filename', '') | ||
| self.parsed_chapters = dictionary.get('parsed_chapters', []) |
There was a problem hiding this comment.
Чтобы заранее определить структуру "parsed_chapters" (а не вспоминать потом, как она выглядит и что в ней лежит) используйте pymodm.EmbeddedMongoModel (не будет создавать отдельную коллекцию, но позволит описать структуру одного раздела / списка разделов) - об этом тоже ранее говорил
There was a problem hiding this comment.
Исправьте название модуля (папки) app/main/reports/pasre_file/parse_file.py
| if "СОДЕРЖАНИЕ" in text: | ||
| continue |
There was a problem hiding this comment.
Вынесите в константу (на уровне модуля) + сделайте кортежем, т.к. в будущем может понадобится пропускать и другие разделы
| chapters = [] | ||
| for chapter in docx.chapters: | ||
| head = chapter["styled_text"]["text"] | ||
| if "ПРИЛОЖЕНИЕ" in head: |
There was a problem hiding this comment.
Аналогично комментарию выше про содержание
| return chapters | ||
|
|
||
|
|
||
| def parse_chapters(docx): |
There was a problem hiding this comment.
насколько отличается от DocxUploader.make_chapters, можно ли привести всё к одному формату разделов (или преобразовать результат одной функции в нужный формат)?
Опасение простое - чем больше мест, где мы парсим файлы (по-разному или одинаково), тем сложнее потом их менять
There was a problem hiding this comment.
Создайте app/celery_tasks и перенесите туда все модули с celery-задачами (т.к. их становится всё больше - лучше держать обособленно)
| TASK_RETRY_COUNTDOWN = 30 | ||
| SOFT_TIME_LIMIT_FOR_CALLBACK = 30 | ||
| MAX_RETRIES = 1 | ||
| TASK_SOFT_TIME_LIMIT = 120 |
There was a problem hiding this comment.
Можно ли вынести в отдельный celery-конфиг для этого модуля? + возможно туда же настройки про тессеракт
| cpuset: ${CONTAINER_CPU:-0-1} | ||
|
|
||
| tesseract_worker: | ||
| image: document_insight_system_image |
There was a problem hiding this comment.
замените на dis:worker-image-${IMAGE_VERSION} (логика образов была немного обновлена) - из-за этого пока CI будет падать
|
Для новых моделей БД и методов организуйте всё согласованно с #585 (в отдельных модулях модели, в отдельных методы) - по возможности, вмержите ветку из PR к себе (там немного конфликтов, но они затрагивают вашу новую логику - не стал трогать) |

No description provided.