Yermek68 commited on
Commit
7b6676b
·
verified ·
1 Parent(s): baa43de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +138 -35
app.py CHANGED
@@ -3,7 +3,21 @@ from transformers import pipeline
3
  import pdfplumber
4
  import os
5
 
6
- # --- Ленивая загрузка модели ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  summarizer = None
8
 
9
  def load_model():
@@ -15,9 +29,13 @@ def load_model():
15
  )
16
  return summarizer
17
 
18
- # --- Безопасное чтение PDF ---
19
- def extract_pdf_text(path):
 
 
20
  text = ""
 
 
21
  try:
22
  with pdfplumber.open(path) as pdf:
23
  for page in pdf.pages:
@@ -26,59 +44,144 @@ def extract_pdf_text(path):
26
  text += chunk + "\n"
27
  except Exception as e:
28
  return "", f"Ошибка при чтении PDF: {e}"
29
- return text, None
30
 
31
- # --- Универсальное чтение файла ---
32
- def read_file(path):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  if not path:
34
  return "", "Файл не передан."
 
35
  path = str(path).strip()
 
36
 
37
- if path.lower().endswith(".pdf"):
38
  return extract_pdf_text(path)
39
 
 
40
  try:
41
  with open(path, "r", encoding="utf-8", errors="ignore") as f:
42
  return f.read(), None
43
  except Exception as e:
44
  return "", f"Ошибка при чтении TXT: {e}"
45
 
46
- # --- Основная функция ---
47
- def summarize_file(path):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  text, err = read_file(path)
49
  if err:
50
- return f"⚠️ {err}"
51
 
52
  if not text.strip():
53
- return "⚠️ Не удалось извлечь текст."
54
-
55
- if len(text) < 80:
56
- return "⚠️ Слишком мало текста для суммаризации."
57
 
 
58
  model = load_model()
59
 
60
- # Ограничиваем текст для избежания OOM
61
- text = text[:4000]
 
62
 
63
- try:
64
- summary = model(
65
- text,
66
- max_length=180,
67
- min_length=60,
68
- do_sample=False
69
- )
70
- return summary[0]["summary_text"]
71
- except Exception as e:
72
- return f"⚠️ Ошибка суммаризации: {e}"
73
-
74
- # --- Интерфейс Gradio ---
75
- demo = gr.Interface(
76
- fn=summarize_file,
77
- inputs=gr.File(type="filepath", label="Загрузите файл (.pdf или .txt)"),
78
- outputs=gr.Textbox(label="Результат суммаризации"),
79
- title="Eroha Summarizer 🧠",
80
- description="Загрузите документ (PDF или TXT), и модель создаст краткое резюме."
81
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
  if __name__ == "__main__":
84
  demo.launch()
 
3
  import pdfplumber
4
  import os
5
 
6
+ # OCR
7
+ try:
8
+ import pytesseract
9
+ from pdf2image import convert_from_path
10
+ from PIL import Image
11
+ OCR_AVAILABLE = True
12
+ except ImportError:
13
+ OCR_AVAILABLE = False
14
+
15
+ # DOCX / PDF экспорт
16
+ from docx import Document
17
+ from fpdf import FPDF
18
+
19
+ # ---------- МОДЕЛЬ ----------
20
+
21
  summarizer = None
22
 
23
  def load_model():
 
29
  )
30
  return summarizer
31
 
32
+ # ---------- ЧТЕНИЕ ФАЙЛА ----------
33
+
34
+ def extract_pdf_text(path: str):
35
+ """Пытаемся вытащить текст из PDF. Если текста нет – пробуем OCR."""
36
  text = ""
37
+
38
+ # 1) обычный текстовый PDF
39
  try:
40
  with pdfplumber.open(path) as pdf:
41
  for page in pdf.pages:
 
44
  text += chunk + "\n"
45
  except Exception as e:
46
  return "", f"Ошибка при чтении PDF: {e}"
 
47
 
48
+ if text.strip():
49
+ return text, None
50
+
51
+ # 2) если текст не найден – пробуем OCR
52
+ if not OCR_AVAILABLE:
53
+ return "", "PDF выглядит как скан (изображение). Для OCR нужно pytesseract + tesseract-ocr."
54
+
55
+ try:
56
+ images = convert_from_path(path, dpi=200)
57
+ ocr_text = ""
58
+ for img in images:
59
+ ocr_text += pytesseract.image_to_string(img) + "\n"
60
+ if not ocr_text.strip():
61
+ return "", "OCR не смог распознать текст в этом PDF."
62
+ return ocr_text, None
63
+ except Exception as e:
64
+ return "", f"Ошибка OCR при обработке PDF: {e}"
65
+
66
+
67
+ def read_file(path: str):
68
  if not path:
69
  return "", "Файл не передан."
70
+
71
  path = str(path).strip()
72
+ lower = path.lower()
73
 
74
+ if lower.endswith(".pdf"):
75
  return extract_pdf_text(path)
76
 
77
+ # TXT / другие текстовые файлы
78
  try:
79
  with open(path, "r", encoding="utf-8", errors="ignore") as f:
80
  return f.read(), None
81
  except Exception as e:
82
  return "", f"Ошибка при чтении TXT: {e}"
83
 
84
+ # ---------- ЧАНКИНГ ТЕКСТА ----------
85
+
86
+ def chunk_text(text: str, max_chars: int = 2500):
87
+ """Режем длинный текст на куски, стараясь обрезать по точкам."""
88
+ chunks = []
89
+ while len(text) > max_chars:
90
+ cut = text[:max_chars]
91
+ last_dot = cut.rfind(".")
92
+ if last_dot != -1:
93
+ cut = cut[:last_dot + 1]
94
+ chunks.append(cut)
95
+ text = text[len(cut):]
96
+ chunks.append(text)
97
+ return chunks
98
+
99
+ # ---------- СОХРАНЕНИЕ РЕЗЮМЕ В DOCX/PDF ----------
100
+
101
+ def save_docx(summary: str) -> str:
102
+ doc = Document()
103
+ doc.add_heading("Eroha Summarizer – Резюме документа", level=1)
104
+ for paragraph in summary.split("\n"):
105
+ doc.add_paragraph(paragraph)
106
+ path = "/tmp/summary.docx"
107
+ doc.save(path)
108
+ return path
109
+
110
+ def save_pdf(summary: str) -> str:
111
+ pdf = FPDF()
112
+ pdf.add_page()
113
+ pdf.set_auto_page_break(auto=True, margin=15)
114
+ pdf.set_font("Arial", size=12)
115
+
116
+ for line in summary.split("\n"):
117
+ # multi_cell сам переносит строки
118
+ pdf.multi_cell(0, 8, line)
119
+ path = "/tmp/summary.pdf"
120
+ pdf.output(path)
121
+ return path
122
+
123
+ # ---------- ОСНОВНАЯ ФУНКЦИЯ ----------
124
+
125
+ def summarize_file(path: str):
126
  text, err = read_file(path)
127
  if err:
128
+ return f"⚠️ {err}", None, None
129
 
130
  if not text.strip():
131
+ return "⚠️ Не удалось извлечь текст из файла.", None, None
 
 
 
132
 
133
+ # Модель
134
  model = load_model()
135
 
136
+ # Чанкинг
137
+ chunks = chunk_text(text, max_chars=2500)
138
+ partial_summaries = []
139
 
140
+ for chunk in chunks:
141
+ if not chunk.strip():
142
+ continue
143
+ try:
144
+ summary = model(
145
+ chunk,
146
+ max_length=180,
147
+ min_length=60,
148
+ do_sample=False
149
+ )
150
+ partial_summaries.append(summary[0]["summary_text"])
151
+ except Exception as e:
152
+ partial_summaries.append(f"[Ошибка в блоке суммаризации: {e}]")
153
+
154
+ if not partial_summaries:
155
+ return "⚠️ Не удалось создать резюме.", None, None
156
+
157
+ final_summary = "\n\n".join(partial_summaries)
158
+
159
+ # Файлы экспорта
160
+ docx_path = save_docx(final_summary)
161
+ pdf_path = save_pdf(final_summary)
162
+
163
+ return final_summary, docx_path, pdf_path
164
+
165
+ # ---------- ИНТЕРФЕЙС GRADIO ----------
166
+
167
+ with gr.Blocks() as demo:
168
+ gr.Markdown("# Eroha Summarizer 🧠")
169
+ gr.Markdown("Загрузите документ (PDF или TXT), и модель создаст краткое резюме с возможностью скачивания DOCX и PDF.")
170
+
171
+ with gr.Row():
172
+ file_input = gr.File(type="filepath", label="Загрузите файл (.pdf или .txt)")
173
+ with gr.Column():
174
+ summary_output = gr.Textbox(label="Результат суммаризации", lines=20)
175
+ docx_output = gr.File(label="Скачать DOCX")
176
+ pdf_output = gr.File(label="Скачать PDF")
177
+
178
+ submit_btn = gr.Button("Запустить суммаризацию")
179
+
180
+ submit_btn.click(
181
+ fn=summarize_file,
182
+ inputs=file_input,
183
+ outputs=[summary_output, docx_output, pdf_output]
184
+ )
185
 
186
  if __name__ == "__main__":
187
  demo.launch()