import streamlit as st
import os
import re
import tempfile
from PyPDF2 import PdfReader, PdfWriter
from io import BytesIO
import fitz  # PyMuPDF
import zipfile
import pytesseract
from PIL import Image
import numpy as np

# Убедитесь, что tesseract установлен и доступен в PATH
# Если не установлен, скачайте и установите его с https://github.com/UB-Mannheim/tesseract/wiki

# Настройка страницы приложения Streamlit
st.set_page_config(page_title="Автоматическое разделение PDF на главы", layout="wide")

# Функция для очистки имени файла от недопустимых символов
def sanitize_filename(name):
    """
    Заменяет запрещенные символы в имени файла на подчеркивание.
    """
    return re.sub(r'[\\/*?:"<>|]', "_", name)

# Функция для извлечения текста из страницы с помощью OCR
def ocr_extract_text(page):
    """
    Извлекает текст из страницы PDF с помощью OCR (pytesseract).
    """
    pix = page.get_pixmap()
    img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
    text = pytesseract.image_to_string(img, lang='rus+eng')  # Указываем языки распознавания
    return text

# Функция для извлечения текста и заголовков из PDF
def extract_text_and_headings(pdf_path):
    """
    Извлекает текст и потенциальные заголовки из каждой страницы PDF.
    Возвращает список словарей с информацией о каждой странице.
    """
    pages_info = []
    try:
        doc = fitz.open(pdf_path)
        for page_num in range(len(doc)):
            page_info = {'page_num': page_num, 'text': '', 'potential_headings': []}
            page = doc[page_num]
            text = page.get_text()
            if not text:
                # Если текст не извлечен, используем OCR
                text = ocr_extract_text(page)
            page_info['text'] = text

            # Анализируем текст и структуру страницы для обнаружения потенциальных заголовков
            potential_headings = []
            blocks = page.get_text("dict")["blocks"]
            for block in blocks:
                if "lines" in block:
                    for line in block["lines"]:
                        for span in line["spans"]:
                            span_text = span["text"].strip()
                            font_size = span.get("size", 0)
                            bbox = span.get("bbox", [0, 0, 0, 0])
                            y0 = bbox[1]  # Верхняя координата текста
                            # Проверяем, находится ли текст в верхней части страницы и имеет ли больший шрифт
                            if y0 < page.rect.height * 0.3 and font_size >= 12:
                                # Проверяем, содержит ли текст ключевые слова
                                if re.match(r'^(Глава|Раздел|Часть)\b', span_text, re.IGNORECASE) or font_size >= 14:
                                    potential_headings.append(span_text)
            page_info['potential_headings'] = potential_headings
            pages_info.append(page_info)
        doc.close()
    except Exception as e:
        st.write(f"Ошибка при анализе PDF: {e}")
    return pages_info

# Функция для определения границ глав
def detect_chapter_boundaries(pages_info):
    """
    Определяет границы глав на основе обнаруженных заголовков и их расположения.
    """
    chapter_starts = []
    for page_info in pages_info:
        page_num = page_info['page_num']
        potential_headings = page_info['potential_headings']
        if potential_headings:
            # Если на странице есть потенциальные заголовки, считаем ее началом новой главы
            chapter_starts.append(page_num)
    # Убираем дубликаты и сортируем список
    chapter_starts = sorted(set(chapter_starts))
    return chapter_starts

# Функция для разделения PDF на главы на основе обнаруженных границ
def split_pdf_by_chapters(pdf_path, chapter_starts, pages_info):
    """
    Разделяет исходный PDF на главы, используя обнаруженные границы глав.
    Возвращает список с данными о главах.
    """
    chapters = []
    try:
        reader = PdfReader(pdf_path)
        total_pages = len(reader.pages)
        chapter_starts.append(total_pages)  # Добавляем конечную страницу
        for i in range(len(chapter_starts) - 1):
            start_page = chapter_starts[i]
            end_page = chapter_starts[i+1]

            writer = PdfWriter()
            for page_num in range(start_page, end_page):
                writer.add_page(reader.pages[page_num])

            # Получаем название главы из потенциального заголовка
            chapter_title = f"Глава_{i+1}"
            page_text = pages_info[start_page]['text']
            # Ищем первую строку текста для названия главы
            lines = page_text.strip().split('\n')
            if lines:
                chapter_title_line = lines[0]
                if len(chapter_title_line) > 0:
                    chapter_title = sanitize_filename(chapter_title_line)[:50]  # Ограничиваем длину названия

            # Создаем имя файла для главы
            output_filename = f"{chapter_title}_стр_{start_page+1}-{end_page}.pdf"
            # Сохраняем новый PDF в байтовый поток
            output_bytes = BytesIO()
            writer.write(output_bytes)
            output_bytes.seek(0)
            chapters.append({
                'title': chapter_title,
                'start_page': start_page,
                'end_page': end_page - 1,
                'file': output_bytes
            })
    except Exception as e:
        st.write(f"Ошибка при разделении PDF: {e}")
    return chapters

# Главная функция приложения
def main():
    st.title("Автоматическое разделение PDF на главы")

    # ---- Загрузка PDF файла ----
    uploaded_file = st.file_uploader("Выберите PDF файл", type=["pdf"])

    if uploaded_file is not None:
        st.write("Файл успешно загружен. Обрабатываем...")
        try:
            # Сохраняем загруженный файл во временное хранилище
            with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
                tmp_file.write(uploaded_file.getvalue())
                tmp_file_path = tmp_file.name

            # Извлекаем текст и потенциальные заголовки из каждой страницы
            pages_info = extract_text_and_headings(tmp_file_path)

            # Проверяем, удалось ли извлечь текст
            if not any(page['text'] for page in pages_info):
                st.error("Не удалось извлечь текст из документа. Возможно, документ является отсканированным изображением без текстового слоя.")
                return

            # Обнаруживаем границы глав
            chapter_starts = detect_chapter_boundaries(pages_info)

            # Если не удалось обнаружить главы, предлагаем альтернативу
            if not chapter_starts:
                st.warning("Автоматически определить главы не удалось. Все содержимое будет сохранено в один файл.")
                chapter_starts = [0]

            # Разделяем PDF на главы на основе обнаруженных границ
            chapters = split_pdf_by_chapters(tmp_file_path, chapter_starts, pages_info)

            if chapters:
                st.success(f"Документ успешно разделен на главы.")
                # Отображаем информацию о главах
                for chapter in chapters:
                    st.write(f"{chapter['title']}: страницы {chapter['start_page']+1}-{chapter['end_page']+1}")
                # Предлагаем скачать все главы в виде ZIP архива
                zip_buffer = BytesIO()
                with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
                    for chapter in chapters:
                        filename = f"{chapter['title']}.pdf"
                        zip_file.writestr(filename, chapter['file'].getvalue())
                zip_buffer.seek(0)
                st.download_button(
                    label="Скачать все главы в формате ZIP",
                    data=zip_buffer,
                    file_name="Разделенные_главы.zip",
                    mime="application/zip"
                )
            else:
                st.error("Не удалось разделить документ на главы.")
            os.unlink(tmp_file_path)
        except Exception as e:
            st.error(f"Произошла ошибка при обработке файла: {e}")

if __name__ == "__main__":
    main()
добавь в названия файлов глав не только глава 1 глава 2 и тд а ещё и полные названия самих глав  - их оглавления