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()