|
import language_tool_python |
|
import openai |
|
import streamlit as st |
|
import subprocess |
|
from search_errors_logic import check_text |
|
import html |
|
import docx |
|
import mammoth |
|
from io import BytesIO |
|
|
|
is_java_installed = False |
|
|
|
def install_java(): |
|
global is_java_installed |
|
if is_java_installed: return |
|
try: |
|
|
|
subprocess.run(["apt-get", "update"], check=True) |
|
subprocess.run(["apt-get", "install", "-y", "openjdk-17-jdk"], check=True) |
|
|
|
is_java_installed = True |
|
except Exception as e: |
|
st.error(f"Ошибка установки Java: {e}") |
|
|
|
|
|
@st.cache_resource |
|
def load_assets(): |
|
openai.api_key = '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' |
|
|
|
|
|
tool = None |
|
return tool |
|
|
|
|
|
def extract_text_from_docx(file): |
|
text = mammoth.convert_to_markdown(file).value |
|
for symbol in ".,!?()[]:;": |
|
text = text.replace(f"\{symbol}", symbol) |
|
return text |
|
|
|
|
|
def main(): |
|
st.markdown(""" |
|
<style> |
|
/* Сохраняем белый текст для темной темы */ |
|
.stApp, .stTextInput, .stTextArea, .stMarkdown { |
|
color: white; |
|
} |
|
|
|
/* цвет фона */ |
|
.stApp { |
|
background-color: #0E1117; |
|
} |
|
|
|
/* Специальный стиль для текста внутри выделенных ошибок */ |
|
.error-highlight { |
|
background-color: #ffe066; |
|
border-bottom: 2px dotted #ff9900; |
|
position: relative; |
|
color: black !important; /* Принудительно черный текст в выделениях */ |
|
} |
|
|
|
/* Стиль для контейнера с результатом */ |
|
.result-container { |
|
background: rgba(255, 255, 255, 0.1); |
|
padding: 20px; |
|
border-radius: 8px; |
|
border: 1px solid #444; |
|
white-space: pre-wrap; |
|
font-family: monospace; |
|
} |
|
|
|
/* Основные стили для белого текста */ |
|
body, .stApp, .stTextInput, .stTextArea, .stMarkdown, |
|
.stRadio, .stButton, .stFileUploader, .stAlert, |
|
.stSuccess, .stWarning, .stError, .stInfo { |
|
color: white !important; |
|
} |
|
|
|
/* Текст в полях ввода */ |
|
.stTextInput input, .stTextArea textarea { |
|
color: white !important; |
|
} |
|
|
|
/* Текст в radio кнопках */ |
|
.stRadio label { |
|
color: white !important; |
|
} |
|
|
|
/* Текст в кнопках */ |
|
.stButton button { |
|
color: white !important; |
|
} |
|
|
|
/* Текст в загрузчике файлов */ |
|
.stFileUploader label { |
|
color: white !important; |
|
} |
|
|
|
/* Заголовки */ |
|
h1, h2, h3, h4, h5, h6 { |
|
color: white !important; |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
st.title('Проверка орфографии') |
|
|
|
|
|
input_mode = st.radio( |
|
"Выберите способ ввода текста:", |
|
("Ввести текст вручную", "Загрузить Word документ"), |
|
horizontal=True |
|
) |
|
|
|
text = "" |
|
if input_mode == "Загрузить Word документ": |
|
uploaded_file = st.file_uploader("Загрузите Word документ", type=['docx']) |
|
if uploaded_file is not None: |
|
try: |
|
text = extract_text_from_docx(uploaded_file) |
|
st.text_area("Текст из документа:", value=text, height=200, key="docx_text") |
|
except Exception as e: |
|
st.error(f"Ошибка при чтении файла: {e}") |
|
else: |
|
text = st.text_area("Введите текст для проверки:", height=200, key="manual_text") |
|
|
|
tool = load_assets() |
|
|
|
if st.button('Проверить текст'): |
|
if not text.strip(): |
|
st.warning("Введите текст для проверки") |
|
else: |
|
text, errors = check_text(text, tool, mode="chat_gpt", highlight_mode=True) |
|
|
|
if not errors: |
|
st.success("Ошибок не найдено.") |
|
else: |
|
sorted_errors = sorted(errors, key=lambda x: x['start']) |
|
|
|
errors_for_higlight = [sorted_errors[0].copy()] |
|
for error in sorted_errors[1:]: |
|
if errors_for_higlight[-1]["end"] >= error["start"]: |
|
errors_for_higlight[-1]["end"] = max(errors_for_higlight[-1]["end"], error["end"]) |
|
else: |
|
errors_for_higlight.append(error) |
|
|
|
highlighted = [] |
|
last_pos = 0 |
|
|
|
for error in errors_for_higlight: |
|
highlighted.append(html.escape(text[last_pos:error['start']])) |
|
|
|
highlighted.append( |
|
f'<span style="background-color: #ffe066; border-bottom: 2px dotted #ff9900; ' |
|
f'position: relative;" title="{html.escape(error["message"])}">' |
|
f'{html.escape(text[error["start"]:error["end"]])}' |
|
f'</span>' |
|
) |
|
|
|
last_pos = error['end'] |
|
|
|
highlighted.append(html.escape(text[last_pos:])) |
|
|
|
html_content = f""" |
|
<div style=" |
|
background: white; |
|
padding: 20px; |
|
border-radius: 8px; |
|
border: 1px solid #ddd; |
|
white-space: pre-wrap; |
|
font-family: monospace; |
|
color: #000000; |
|
"> |
|
{''.join(highlighted)} |
|
</div> |
|
""" |
|
|
|
st.markdown("_**Как это работает:** Если ошибки находятся рядом, они группируются под одним номером. Посмотрите комментарий — там будут все замечания по этому участку текста._") |
|
st.markdown("### Результат проверки:") |
|
st.markdown(html_content, unsafe_allow_html=True) |
|
|
|
st.markdown("### Найденные ошибки:") |
|
errors_in_order_for_print = sorted(errors, key=lambda x: x['end']) |
|
for i, error in enumerate(errors_in_order_for_print, 1): |
|
st.markdown(f"{i}. {error['message']}") |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|