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