sterepando commited on
Commit
31b0bf1
·
verified ·
1 Parent(s): fc0d9d2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -46
app.py CHANGED
@@ -3,35 +3,33 @@ import uvicorn
3
  from PIL import Image
4
  from fastapi import FastAPI, UploadFile, File, Response
5
  import torch
6
- from transformers import AutoModelForImageTextToText, AutoTokenizer, AutoImageProcessor
7
 
8
  # --- 1. Глобальная загрузка компонентов ---
9
  model = None
10
- tokenizer = None
11
- image_processor = None
12
  device = "cpu"
13
 
14
  try:
15
- print(">>> Инициализация загрузки LightOnOCR-1B (Fixed VLM pipeline)...")
16
 
17
  device = "cuda" if torch.cuda.is_available() else "cpu"
18
  print(f">>> Устройство: {device}")
19
 
20
  repo_id = "lightonai/LightOnOCR-1B-1025"
21
 
22
- # 1. Загружаем токенизатор
23
- tokenizer = AutoTokenizer.from_pretrained(repo_id)
 
 
24
 
25
- # 2. Загружаем обработчик изображений
26
- # Используем AutoImageProcessor, он должен вернуть правильный класс
27
- image_processor = AutoImageProcessor.from_pretrained(repo_id)
28
-
29
- # 3. Загружаем модель
30
  dtype = torch.bfloat16 if device == "cuda" else torch.float32
31
  model = AutoModelForImageTextToText.from_pretrained(
32
  repo_id,
33
  torch_dtype=dtype,
34
- low_cpu_mem_usage=True
 
35
  ).to(device)
36
 
37
  print(">>> Все компоненты успешно загружены!")
@@ -39,11 +37,11 @@ try:
39
  except Exception as e:
40
  print(f"КРИТИЧЕСКАЯ ОШИБКА загрузки: {e}")
41
 
42
- app = FastAPI(title="LightOnOCR Robust API", version="4.0.0")
43
 
44
  @app.post("/api/ocr")
45
  async def run_ocr(file: UploadFile = File(...)):
46
- if model is None:
47
  return Response(content="Сервер не готов.", status_code=503)
48
 
49
  try:
@@ -51,51 +49,43 @@ async def run_ocr(file: UploadFile = File(...)):
51
  contents = await file.read()
52
  image = Image.open(io.BytesIO(contents)).convert("RGB")
53
 
54
- # 2. Подготовка визуальных данных
55
- # ВАЖНО: Мы не просто берем pixel_values, мы берем ВСЕ, что вернет процессор.
56
- # Современные модели требуют 'image_sizes' или 'aspect_ratio_ids'.
57
- vision_outputs = image_processor(images=image, return_tensors="pt")
58
-
59
- # Переносим тензоры на устройство (GPU/CPU)
60
- # Создаем словарь аргументов для генерации
61
- gen_kwargs = {
62
- "max_new_tokens": 1024,
63
- "do_sample": False,
64
- "pad_token_id": tokenizer.pad_token_id
65
- }
66
-
67
- # Автоматически добавляем все выходы процессора (pixel_values, image_sizes и т.д.)
68
- for key, value in vision_outputs.items():
69
- if isinstance(value, torch.Tensor):
70
- gen_kwargs[key] = value.to(device)
71
- else:
72
- gen_kwargs[key] = value
73
-
74
- # 3. Подготовка текста
75
- # Стандартный формат промпта для LLaVA-подобных моделей
76
  prompt = "<image>\nTranscribe the text in this image."
77
 
78
- text_inputs = tokenizer(prompt, return_tensors="pt")
79
- gen_kwargs["input_ids"] = text_inputs["input_ids"].to(device)
80
- gen_kwargs["attention_mask"] = text_inputs["attention_mask"].to(device)
 
 
 
 
81
 
82
  # 4. Г��нерация
83
- # Теперь gen_kwargs содержит и pixel_values, и image_sizes (если они нужны модели)
84
  with torch.inference_mode():
85
- generated_ids = model.generate(**gen_kwargs)
 
 
 
 
 
86
 
87
  # 5. Декодирование
88
- generated_text = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
89
 
90
- # Очистка от артефактов промпта (опционально)
91
- # Часто модель возвращает "Transcribe... \n Результат". Уберем промпт.
92
- clean_text = generated_text.replace("Transcribe the text in this image.", "").strip()
93
 
 
 
 
 
94
  return {"text": clean_text}
95
 
96
  except Exception as e:
97
  import traceback
98
- traceback.print_exc() # Печатаем полный лог ошибки в консоль сервера
99
  return Response(content=f"Server Error: {str(e)}", status_code=500)
100
 
101
  @app.get("/")
 
3
  from PIL import Image
4
  from fastapi import FastAPI, UploadFile, File, Response
5
  import torch
6
+ from transformers import AutoModelForImageTextToText, AutoProcessor
7
 
8
  # --- 1. Глобальная загрузка компонентов ---
9
  model = None
10
+ processor = None
 
11
  device = "cpu"
12
 
13
  try:
14
+ print(">>> Инициализация загрузки LightOnOCR-1B (с trust_remote_code=True)...")
15
 
16
  device = "cuda" if torch.cuda.is_available() else "cpu"
17
  print(f">>> Устройство: {device}")
18
 
19
  repo_id = "lightonai/LightOnOCR-1B-1025"
20
 
21
+ # 1. Загружаем процессор
22
+ # ВАЖНО: trust_remote_code=True позволяет загрузить кастомный код процессора из репозитория,
23
+ # который умеет правильно обрабатывать аргумент 'images' и вставлять токены.
24
+ processor = AutoProcessor.from_pretrained(repo_id, trust_remote_code=True)
25
 
26
+ # 2. Загружаем модель
 
 
 
 
27
  dtype = torch.bfloat16 if device == "cuda" else torch.float32
28
  model = AutoModelForImageTextToText.from_pretrained(
29
  repo_id,
30
  torch_dtype=dtype,
31
+ low_cpu_mem_usage=True,
32
+ trust_remote_code=True
33
  ).to(device)
34
 
35
  print(">>> Все компоненты успешно загружены!")
 
37
  except Exception as e:
38
  print(f"КРИТИЧЕСКАЯ ОШИБКА загрузки: {e}")
39
 
40
+ app = FastAPI(title="LightOnOCR Final API", version="5.0.0")
41
 
42
  @app.post("/api/ocr")
43
  async def run_ocr(file: UploadFile = File(...)):
44
+ if model is None or processor is None:
45
  return Response(content="Сервер не готов.", status_code=503)
46
 
47
  try:
 
49
  contents = await file.read()
50
  image = Image.open(io.BytesIO(contents)).convert("RGB")
51
 
52
+ # 2. Формирование промпта
53
+ # Для этой модели обычно достаточно простого промпта, но важно,
54
+ # чтобы процессор сам обработал вставку <image> токенов.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  prompt = "<image>\nTranscribe the text in this image."
56
 
57
+ # 3. Обработка через процессор
58
+ # Теперь, с trust_remote_code=True, этот вызов должен работать корректно
59
+ # и вернуть input_ids, pixel_values и, возможно, image_sizes.
60
+ inputs = processor(text=prompt, images=image, return_tensors="pt")
61
+
62
+ # Переносим все тензоры на устройство
63
+ inputs = {k: v.to(device) for k, v in inputs.items() if isinstance(v, torch.Tensor)}
64
 
65
  # 4. Г��нерация
 
66
  with torch.inference_mode():
67
+ generated_ids = model.generate(
68
+ **inputs,
69
+ max_new_tokens=1024,
70
+ do_sample=False,
71
+ pad_token_id=processor.tokenizer.pad_token_id
72
+ )
73
 
74
  # 5. Декодирование
75
+ generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
76
 
77
+ # Очистка результата от промпта (простая эвристика)
78
+ clean_text = generated_text.replace(prompt.replace("<image>", ""), "").strip()
 
79
 
80
+ # Дополнительная очистка, если модель возвращает мусор в начале
81
+ if "Transcribe" in clean_text:
82
+ clean_text = clean_text.split("image.")[-1].strip()
83
+
84
  return {"text": clean_text}
85
 
86
  except Exception as e:
87
  import traceback
88
+ traceback.print_exc()
89
  return Response(content=f"Server Error: {str(e)}", status_code=500)
90
 
91
  @app.get("/")