import streamlit as st import fitz from io import BytesIO from termcolor import colored from docx import Document from helpers import get_mck, parse_doc_days, parse_pdf_oik, parse_doc_oik, get_pdf_blocks, get_doc_blocks, check_percent_before_price from checks import check_correctness from garant import detect_garant_pdf, detect_garant_doc, detect_garant_doc_price from garant_check import check_garant from ikz import get_ikz_pdf, get_ikz_doc from fz93 import get_fz93_doc from htbuilder import HtmlElement, div, ul, li, br, hr, a, p, img, styles, classes, fonts from htbuilder.units import percent, px from htbuilder.funcs import rgba, rgb def image(src_as_string, **style): return img(src=src_as_string, style=styles(**style)) def link(link, text, **style): return a(_href=link, _target="_blank", style=styles(**style))(text) def layout(*args): style = """ """ style_div = styles( #position="fixed", left=0, bottom=0, margin=px(1, 1, 1, 1), width=percent(100), color="#FF4B4B", text_align="center", height="auto", opacity=80 ) style_hr = styles( display="block", margin=px(8, 8, "auto", "auto"), border_style="inset", border_width=px(2) ) body = p() foot = div( style=style_div )( hr( style=style_hr ), body ) st.markdown(style, unsafe_allow_html=True) for arg in args: if isinstance(arg, str): body(arg) elif isinstance(arg, HtmlElement): body(arg) st.markdown(str(foot), unsafe_allow_html=True) def footer(): myargs = [ "При возникновении вопросов по работе приложения обращайтесь в поддержку ", image('https://img.freepik.com/premium-vector/round-telegram-logo-isolated-on-white-background_469489-903.jpg?w=996', width=px(25), height=px(25)), " @Imari_Iv ", br(), #"🇷🇺", '🇷🇺' image('https://img.freepik.com/free-vector/round-russian-flag-background_23-2147816636.jpg?w=996&t=st=1707289958~exp=1707290558~hmac=fb04f57b6a5c662b6df3a2c847ff8160e45f9b93b795112bccc6668ced7d5837', width=px(25), height=px(25)), #image( "https://yoursticker.ru/wp-content/uploads/2021/12/moskovskoj-300x225.jpg", width=px(25), height=px(25)), # "   with ❤️ My 🏠 is 🇷🇺 :ru: Я люблю 🇷🇺 :flag_ru: by  ", #link("https://twitter.com/ChristianKlose3", "@ChristianKlose3"), br(), #link("https://www.buymeacoffee.com/ChrisChross", image('https://ibb.co/d0sBsNv'), ), ] layout(*myargs) def main(): st.title("Закупочный Патруль") pdf_files_list = [] docx_files_list = [] languages = { #перевод кнопок "EN": { "button": "Browse Files", "instructions": "Drag and drop files here", "limits": "Limit 200MB per file", }, "RU": { "button": "Добавить", "instructions": "Загрузите файл", "limits": "Ограничение объема файла 200MB", }, } lang = st.radio("", options=["EN", "RU"],index=1, horizontal=True) hide_label = ( """ """.replace( "BUTTON_TEXT", languages.get(lang).get("button") #.get(lang) ) .replace("INSTRUCTIONS_TEXT", languages.get(lang).get("instructions")) #.get(lang) .replace("FILE_LIMITS", languages.get(lang).get("limits")) #get(lang) ) st.markdown(hide_label, unsafe_allow_html=True) # Кнопка для загрузки PDF файла pdf_files = st.file_uploader("Загрузите PDF Извещения", type=["pdf"], accept_multiple_files=True) for pdf_file in pdf_files: bytes_data = pdf_file.read() pdf_doc = fitz.open(stream=bytes_data, filetype="pdf") st.write("Файл Извещения:", pdf_file.name) #st.write(pdf_doc[0].get_text()) pdf_files_list.append(pdf_file) # Добавляем файл в список # Кнопка для загрузки DOCX файла docx_files = st.file_uploader("Загрузите DOCX файл ПК", type=["docx"], accept_multiple_files=True) for docx_file in docx_files: doc_bytes = docx_file.read() doc = Document(BytesIO(doc_bytes)) #st.write(doc.paragraphs[0].text) st.write("файл ПК:", docx_file.name) docx_files_list.append(docx_file) # Добавляем файл в список # Кнопка начала проверки if st.button("Проверить", type="primary"): #if pdf_file is not None and docx_file is not None: if len(pdf_files_list) > 0 and len(docx_files_list) > 0: print("=" * 80) st.write("_" * 80) """ ЧАСТЬ 1 "Обеспечение исполнения контракта" """ # Логика проверки файлов и формирования комментария try: paragraphs = get_doc_blocks(doc) pdf_blocks = get_pdf_blocks(pdf_doc) percent_before_price = check_percent_before_price(paragraphs) ( oik_pdf, check_if_3_30_present, check_if_24_22_present ) = parse_pdf_oik(pdf_blocks, debug_print=False) print(f"{check_if_3_30_present = }\n{check_if_24_22_present = }") ( oik_docx, ot_tseni_kontracta, ot_nachalnoi_tseni_kontracta, ot_max_znacenia_tseni_kontracta ) = parse_doc_oik(paragraphs) if oik_docx: clean_oik_docx = ( oik_docx[0] .replace(" процент", "%") .replace(" %", '%') ) else: clean_oik_docx = "" if oik_pdf: clean_oik_pdf = oik_pdf[0] else: clean_oik_pdf = "" MCKs = get_mck(pdf_blocks) clean_days_docx = parse_doc_days(paragraphs) print(f"{clean_oik_docx = }\n{clean_oik_pdf = }") # print("MCKs", MCKs) except Exception as ex: #print(colored("ERROR при прочтении, пожалуйста проверьте документ!", 'magenta')) st.write(f"ERROR при прочтении {ex}") #st.write(" :magenta[ERROR при прочтении, пожалуйста проверьте документ!]") clean_days_docx, MCKs, clean_oik_pdf, clean_oik_doсx = None, None, None, None try: if MCKs is None: pass elif len(MCKs) >= 1: if len(MCKs) > 1: print("MCK Не один") check_correctness( check_if_3_30_present=check_if_3_30_present, check_if_24_22_present=check_if_24_22_present, ot_max_znacenia_tseni_kontracta=ot_max_znacenia_tseni_kontracta, clean_oik_pdf=clean_oik_pdf, clean_oik_docx=clean_oik_docx, ot_nachalnoi_tseni_kontracta=ot_nachalnoi_tseni_kontracta, ot_tseni_kontracta=ot_tseni_kontracta, MCKs=MCKs, clean_days_docx=clean_days_docx, percent_before_price=percent_before_price, ) else: print("MCK отсутствует!") except Exception as ex: # print(colored(f"ERROR при сравнении, {ex}", 'magenta')) #st.write(":magenta[ERROR при сравнении, пожалуйста проверьте документ!]") st.write(f"ERROR при сравнении {ex}") # break print("=" * 80) st.write("_" * 80) """ ЧАСТЬ 2 "Обеспечение гарантийных обязательств" """ # Поле для вывода комментария после проверки # result_comment_area = st.text_area(f"Результат проверки : {result_comment}") # достаем параграфы текстовые из документов paragraphs = get_doc_blocks(doc) pdf_blocks = get_pdf_blocks(pdf_doc) try: garant_pdf = detect_garant_pdf(pdf_blocks, debug_print=False) garant_docx = detect_garant_doc(paragraphs, debug_print=False) MCKs = get_mck(pdf_blocks, debug_print=False) price_doc = detect_garant_doc_price(paragraphs, debug_print=False) #print(colored("ERROR при прочтении, пожалуйста проверьте документ!", 'magenta')) except Exception as ex: # st.write(f"ERROR при прочтении ЧАСТЬ 2, ") st.write(f":red[ERROR при прочтении ЧАСТЬ 2, {ex}]") check_garant( garant_pdf=garant_pdf, garant_docx=garant_docx, price_doc=price_doc, MCKs=MCKs ) print("=" * 80) st.write("_" * 80) """ ЧАСТЬ 3 "ИКЗ" """ ikz_pdf = get_ikz_pdf(pdf_blocks) ikz_docx = get_ikz_doc(doc) if ikz_docx and ikz_pdf: ikz_docx_clean = set( [el.replace("-", '') for el in ikz_docx] ) ikz_pdf_clean = set( [el.replace("-", '') for el in ikz_pdf] ) if ikz_docx_clean == ikz_pdf_clean: # print(colored("РАВНЫ", 'green')) st.write(":green[РАВНЫ]") # st.write("РАВНЫ") else: # print(colored("ОШИБКА", 'magenta')) st.write(":red[ОШИБКА]") # st.write("ОШИБКА") for el in sorted(ikz_docx_clean): if el not in ikz_pdf_clean: # print(f"ИКЗ {el} присутствует в .docx, но не в .pdf") st.write(f"ИКЗ {el} присутствует в .docx, но не в .pdf") print("-" * 60) st.write("-" * 60) for el in sorted(ikz_pdf_clean): if el not in ikz_docx_clean: # print(f"ИКЗ {el} присутствует в .pdf, но не в .docx") st.write(f"ИКЗ {el} присутствует в .pdf, но не в .docx") else: # print(colored("ПУСТОЕ ЗНАЧЕНИЕ", 'magenta')) st.write(":red[ПУСТОЕ ЗНАЧЕНИЕ]") # st.write("ПУСТОЕ ЗНАЧЕНИЕ") print("=" * 80) st.write("_" * 80) """ ЧАСТЬ 4 "часть 1 статьи 93 ФЗ-44 в ПК" """ fz93_docx = get_fz93_doc(doc) if fz93_docx: # проверка на пустоту, если есть ст.93 - ОШИБКА print(colored("ОШИБКА", 'magenta')) st.write(":red[ОШИБКА]") print("ч. 1 ст. 93 ФЗ в ПК") st.write("ч. 1 ст. 93 ФЗ в ПК") else: print(colored("ВЕРНО", 'green')) st.write(":green[ВЕРНО]") else: st.write("Нет документов для проверки") # Сообщение, если нет загруженных файлов st.header(':blue[ККП МО]:arrow_upper_right:',anchor=None, divider="blue") # expander = st.expander("Информация") # # expander.write("**Руководство пользователя**") # expander.write(" :white_check_mark: Для проверки вашей закупочной документации перед публикацией поместите в " # "первый слот проект Извещения в формате PDF, во второй слот добавьте проект " # "Контракта в формате DOCX.") # expander.write(" :green[Ваш документ не должен быть создан в версии Microsoft Word 97–2003 (.doc)] ") # expander.write(" :white_check_mark: Нажмите кнопку :red[Проверить] ") # expander.write(" :white_check_mark: Посмотрите на результаты проверки блоков закупочной документации. " # " Если ответ :green[ВЕРНО] или :green[РАВНЫ], значит ошибок не обнаружено.") # expander.write( " :white_check_mark: В случае получения результата :red[ОШИБКА] проверьте соответсвующий блок вашей документации.") # expander.write(":blue[ЧАСТЬ 1 ]") # expander.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части" # " 'Обеспечения исполнения Контракта'.") # # expander.write("В случае получения результата :red[ОШИБКА], проверьте ваш документ в соответствии с появившейся инструкцией." # " Не забудьте проверить корректность вычислений.") # expander.write("В случае получения результата :red[ОШИБКА в днях OIK], проверьте правильность срока возврата обеспечения.") # expander.write("В случае получения результата :red[ERROR при прочтении, пожалуйста проверьте документ!] или " # " :red[ERROR при сравнении] - проверьте наличие данного блока в вашей документации.") # # # expander.write(":blue[ЧАСТЬ 2 ]") # expander.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части" # " 'Обеспечения гарантийных обязательств'.") # expander.write("В случае получения результата :red[ОШИБКА], проверьте данный блок в вашем документе в соответствии с появившейся инструкцией." # " Не забудьте проверить корректность вычислений.") # expander.write("В случае получения результата :red[ERROR при прочтении ЧАСТЬ 2] " # " - проверьте наличие данного блока в вашей документации.") # expander.write(":blue[ЧАСТЬ 3 ]") # expander.write("В данном блоке проверяется соответствие кодов ИКЗ в проекте Контракта с кодами Извещения в части" # " 'Идентификационные коды закупки'.") # expander.write("В случае получения результата :red[ОШИБКА], проверьте не совпавшие коды, указанные под ним.") # expander.write(":blue[ЧАСТЬ 4 ]") # expander.write("В данном блоке проверяется отсутствие в проекте Контракта указания на часть 1 статьи 93 ФЗ-44." # " В случае получения результата :red[ОШИБКА], удалите из вашего проекта Контракта данную статью.") # expander.write(" :white_check_mark: Если вам не удалось найти ошибку или возникли иные вопросы по работе приложения" # " - обратитесь в поддержку.") # expander.write(":blue[Для скрытия данного блока повторно нажмите на информационную кнопку]") # Проверяем, существует ли состояние session_state.text_widget и инициализируем его, если нет if "text_widget" not in st.session_state: st.session_state.text_widget = False # # # Создаем кнопку для открытия/закрытия виджета if st.button("i"): st.session_state.text_widget = not st.session_state.text_widget # # # Отображаем виджет, если флаг равен True if st.session_state.text_widget: container = st.container(border=True) container.write("**Руководство пользователя**") container.write(" :white_check_mark: Для проверки вашей закупочной документации поместите в " "первый слот проект Извещения в формате PDF, во второй слот добавьте проект " "Контракта в формате DOCX.") container.write(" :green[Ваш документ не должен быть создан в версии Microsoft Word 97–2003 (.doc)] ") container.write(" :white_check_mark: Нажмите кнопку :red[Проверить] ") container.write(" :white_check_mark: Посмотрите на результаты проверки блоков закупочной документации. " " Если ответ :green[ВЕРНО] или :green[РАВНЫ], значит ошибок не обнаружено.") container.write( " :white_check_mark: В случае получения результата :red[ОШИБКА] проверьте соответсвующий блок вашей документации.") # # # container.write(":blue[ЧАСТЬ 1 ]") container.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части" " 'Обеспечения исполнения Контракта'.") # container.write("В случае получения результата :red[ОШИБКА]") container.write( " :red[ 1. Если Обеспечение исполнения Контракта указано в Приложении к проекту Контракта проверьте его самостоятельно и проигнорируйте сообщение об ошибке]") container.write( " 2. Проверьте ваш документ в соответствии с появившейся инструкцией.") container.write( " 3. Не забудьте проверить корректность вычислений.") container.write("В случае получения результата :red[ОШИБКА в днях OIK], проверьте правильность срока возврата обеспечения.") container.write("В случае получения результата :red[ERROR при прочтении, пожалуйста проверьте документ!] или " " :red[ERROR при сравнении] - проверьте наличие данного блока в вашей документации.") # # container.write(":blue[ЧАСТЬ 2 ]") container.write("В данном блоке проверяется соответствие условий проекта Контракта с условиями Извещения в части" " 'Обеспечения гарантийных обязательств'.") container.write("В случае получения результата :red[ОШИБКА], проверьте данный блок в вашем документе в соответствии с появившейся инструкцией." " Не забудьте проверить корректность вычислений.") container.write("В случае получения результата :red[ERROR при прочтении ЧАСТЬ 2] " " - проверьте наличие данного блока в вашей документации.") container.write(":blue[ЧАСТЬ 3 ]") container.write("В данном блоке проверяется соответствие кодов ИКЗ в проекте Контракта с кодами Извещения в части" " 'Идентификационные коды закупки'.") container.write("В случае получения результата :red[ОШИБКА], проверьте не совпавшие коды, указанные под ним.") container.write(":blue[ЧАСТЬ 4 ]") container.write("В данном блоке проверяется отсутствие в проекте Контракта указания на часть 1 статьи 93 ФЗ-44." " В случае получения результата :red[ОШИБКА], удалите из вашего проекта Контракта данную статью.") container.write(" :white_check_mark: Если вам не удалось найти ошибку или возникли иные вопросы по работе приложения" " - обратитесь в поддержку.") container.write(":blue[Для скрытия данного блока повторно нажмите на информационную кнопку]") #st.markdown("Here's a bouquet —\ # :tulip::cherry_blossom::rose::hibiscus::sunflower::blossom:") if __name__ == "__main__": main() footer() # show_info()