tddf commited on
Commit
3a8d636
·
verified ·
1 Parent(s): 00e049c

Update Main.py

Browse files
Files changed (1) hide show
  1. Main.py +42 -61
Main.py CHANGED
@@ -5,10 +5,9 @@ import torch
5
  from transformers import LightOnOcrForConditionalGeneration, LightOnOcrProcessor
6
  from PIL import Image
7
 
8
- # Ускоряем скачивание модели
9
  os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
10
 
11
- # ==================== Настройки страницы ====================
12
  st.set_page_config(
13
  page_title="LightOnOCR • Распознай текст",
14
  page_icon="📄",
@@ -16,30 +15,22 @@ st.set_page_config(
16
  initial_sidebar_state="expanded"
17
  )
18
 
19
- # ==================== Кастомный CSS ====================
20
  st.markdown("""
21
- <style>
22
- .main {
23
- background: linear-gradient(180deg, #f8f9fa, #e9f0f7);
24
- }
25
- .header-emoji {
26
- font-size: 3.5rem;
27
- text-align: center;
28
- margin: 15px 0;
29
- }
30
- .result-box {
31
- background: #ffffff;
32
- border-radius: 16px;
33
- padding: 24px;
34
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
35
- border: 1px solid #e5e7eb;
36
- margin-top: 20px;
37
- }
38
- </style>
39
  """, unsafe_allow_html=True)
40
 
41
- # ==================== Загрузка модели ====================
42
- @st.cache_resource(show_spinner="⏳ Загрузка модели LightOnOCR-1B-1025...\nЭто может занять 2–6 минут при первом запуске...")
43
  def load_model():
44
  model_name = "lightonai/LightOnOCR-1B-1025"
45
 
@@ -54,13 +45,20 @@ def load_model():
54
 
55
  processor = LightOnOcrProcessor.from_pretrained(model_name)
56
 
57
- # Исправляем pad_token
58
- if processor.tokenizer.pad_token is None:
59
- processor.tokenizer.pad_token = processor.tokenizer.eos_token
60
-
61
  return processor, model, device, dtype
62
 
63
- # ==================== Загрузка изображения ====================
 
 
 
 
 
 
 
 
 
 
 
64
  def load_image():
65
  uploaded_file = st.file_uploader(
66
  "📸 Загрузите изображение (png, jpg, jpeg, webp)",
@@ -72,71 +70,55 @@ def load_image():
72
  return Image.open(io.BytesIO(image_data)).convert('RGB')
73
  return None
74
 
75
- # ==================== Основной интерфейс ====================
76
- st.markdown('<div class="header-emoji">📄✨</div>', unsafe_allow_html=True)
77
- st.title("LightOnOCR")
78
- st.markdown("**Мгновенное распознавание текста с изображений**")
79
- st.caption("Модель: lightonai/LightOnOCR-1B-1025")
80
-
81
- # Загрузка модели
82
- processor, model, device, dtype = load_model()
83
-
84
- # Сайдбар
85
- with st.sidebar:
86
- st.success(f"✅ Модель загружена на **{device.upper()}**")
87
- st.info("Лучше всего работает с английским текстом, документами и таблицами.")
88
-
89
- # Загрузка изображения
90
  img = load_image()
91
 
92
- # ==================== Распознавание ====================
93
  if st.button("🔍 Распознать текст", use_container_width=True, type="primary"):
94
  if img is None:
95
- st.error("Пожалуйста, сначала загрузите изображение")
96
  else:
97
- with st.spinner("Распознавание текста... (может занять 5–20 секунд на CPU)"):
98
 
99
- # Правильный промпт
100
  conversation = [
101
  {
102
  "role": "user",
103
  "content": [
104
- {"type": "image"},
105
- {"type": "text", "text": "Extract all the text from this image accurately. Preserve original formatting, tables, and line breaks as much as possible."}
106
  ]
107
  }
108
  ]
109
 
110
- # Подготовка входных данных
111
  inputs = processor.apply_chat_template(
112
  conversation,
113
  add_generation_prompt=True,
114
  tokenize=True,
115
  return_dict=True,
116
  return_tensors="pt",
 
117
  images=img
118
  )
119
 
120
- # Перенос на устройство
121
-
122
-
123
- inputs = {
124
  k: (v.to(device=device, dtype=dtype) if v.is_floating_point() else v.to(device))
125
  for k, v in inputs.items()
126
  }
127
 
128
  # Генерация
129
- output_ids = model.generate(
130
  **inputs,
131
  max_new_tokens=2048,
132
  do_sample=False,
133
  temperature=0.0,
134
- num_beams=1,
135
  pad_token_id=processor.tokenizer.pad_token_id,
136
  eos_token_id=processor.tokenizer.eos_token_id,
137
  )
138
 
139
- # Убираем промпт из результата
140
  prompt_length = inputs["input_ids"].shape[1]
141
  generated_ids = output_ids[0, prompt_length:]
142
 
@@ -146,20 +128,19 @@ inputs = {
146
  clean_up_tokenization_spaces=True
147
  ).strip()
148
 
149
- # Результат
150
  st.success("✅ Распознавание завершено!")
151
  st.markdown('<div class="result-box">', unsafe_allow_html=True)
152
  st.subheader("📝 Распознанный текст")
153
- st.code(generated_text, language=None)
154
  st.markdown('</div>', unsafe_allow_html=True)
155
 
156
  st.download_button(
157
- label="💾 Скачать текст как .txt",
158
  data=generated_text,
159
  file_name="recognized_text.txt",
160
  mime="text/plain"
161
  )
162
 
163
- # Подвал
164
  st.markdown("---")
165
  st.caption("Сделано на базе [lightonai/LightOnOCR-1B-1025](https://huggingface.co/lightonai/LightOnOCR-1B-1025)")
 
5
  from transformers import LightOnOcrForConditionalGeneration, LightOnOcrProcessor
6
  from PIL import Image
7
 
8
+ # Ускоряем скачивание на HF Spaces
9
  os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
10
 
 
11
  st.set_page_config(
12
  page_title="LightOnOCR • Распознай текст",
13
  page_icon="📄",
 
15
  initial_sidebar_state="expanded"
16
  )
17
 
18
+ # Простой CSS
19
  st.markdown("""
20
+ <style>
21
+ .main { background: linear-gradient(180deg, #f8f9fa, #e9f0f7); }
22
+ .result-box {
23
+ background: #ffffff;
24
+ border-radius: 16px;
25
+ padding: 24px;
26
+ box-shadow: 0 10px 30px rgba(0,0,0,0.08);
27
+ margin-top: 20px;
28
+ }
29
+ .header-emoji { font-size: 3.5rem; text-align: center; margin: 15px 0; }
30
+ </style>
 
 
 
 
 
 
 
31
  """, unsafe_allow_html=True)
32
 
33
+ @st.cache_resource(show_spinner="⏳ Загрузка модели LightOnOCR-1B-1025...\nЭто может занять 2–6 минут при первом запуске на CPU")
 
34
  def load_model():
35
  model_name = "lightonai/LightOnOCR-1B-1025"
36
 
 
45
 
46
  processor = LightOnOcrProcessor.from_pretrained(model_name)
47
 
 
 
 
 
48
  return processor, model, device, dtype
49
 
50
+ # ====================== Заголовок ======================
51
+ st.markdown('<div class="header-emoji">📄✨</div>', unsafe_allow_html=True)
52
+ st.title("LightOnOCR")
53
+ st.markdown("**Распознавание текста с изображений**")
54
+ st.caption("Модель: lightonai/LightOnOCR-1B-1025")
55
+
56
+ # ====================== Загрузка модели ======================
57
+ processor, model, device, dtype = load_model()
58
+
59
+ st.sidebar.success(f"✅ Модель загружена на **{device.upper()}**")
60
+
61
+ # ====================== Загрузка изображения ======================
62
  def load_image():
63
  uploaded_file = st.file_uploader(
64
  "📸 Загрузите изображение (png, jpg, jpeg, webp)",
 
70
  return Image.open(io.BytesIO(image_data)).convert('RGB')
71
  return None
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  img = load_image()
74
 
75
+ # ====================== Распознавание ======================
76
  if st.button("🔍 Распознать текст", use_container_width=True, type="primary"):
77
  if img is None:
78
+ st.error("Сначала загрузите изображение")
79
  else:
80
+ with st.spinner("Распознавание текста... (может занять 5–20 сек на CPU)"):
81
 
82
+ # Правильный формат для LightOnOCR (только изображение + промпт)
83
  conversation = [
84
  {
85
  "role": "user",
86
  "content": [
87
+ {"type": "image"}, # изображение передаётся автоматически через processor
88
+ {"type": "text", "text": "Extract all the text from this image as accurately as possible. Output clean text with preserved line breaks and formatting."}
89
  ]
90
  }
91
  ]
92
 
93
+ # Подготовка inputs (processor обработает и изображение, и текст)
94
  inputs = processor.apply_chat_template(
95
  conversation,
96
  add_generation_prompt=True,
97
  tokenize=True,
98
  return_dict=True,
99
  return_tensors="pt",
100
+ # Важно: передаём само PIL-изображение
101
  images=img
102
  )
103
 
104
+ # Переносим на устройство
105
+ inputs = {
 
 
106
  k: (v.to(device=device, dtype=dtype) if v.is_floating_point() else v.to(device))
107
  for k, v in inputs.items()
108
  }
109
 
110
  # Генерация
111
+ output_ids = model.generate(
112
  **inputs,
113
  max_new_tokens=2048,
114
  do_sample=False,
115
  temperature=0.0,
116
+ num_beams=1, # для стабильности
117
  pad_token_id=processor.tokenizer.pad_token_id,
118
  eos_token_id=processor.tokenizer.eos_token_id,
119
  )
120
 
121
+ # Убираем входной промпт оставляем только сгенерированный текст
122
  prompt_length = inputs["input_ids"].shape[1]
123
  generated_ids = output_ids[0, prompt_length:]
124
 
 
128
  clean_up_tokenization_spaces=True
129
  ).strip()
130
 
131
+ # Вывод результата
132
  st.success("✅ Распознавание завершено!")
133
  st.markdown('<div class="result-box">', unsafe_allow_html=True)
134
  st.subheader("📝 Распознанный текст")
135
+ st.code(generated_text, language=None) # лучше чем markdown для больших блоков
136
  st.markdown('</div>', unsafe_allow_html=True)
137
 
138
  st.download_button(
139
+ label="💾 Скачать как .txt",
140
  data=generated_text,
141
  file_name="recognized_text.txt",
142
  mime="text/plain"
143
  )
144
 
 
145
  st.markdown("---")
146
  st.caption("Сделано на базе [lightonai/LightOnOCR-1B-1025](https://huggingface.co/lightonai/LightOnOCR-1B-1025)")