File size: 5,920 Bytes
008c86f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
=============================================================
EasyOCR API - Reconocimiento de Texto Rápido
=============================================================
API REST para reconocer texto usando EasyOCR
Optimizado para velocidad - Ideal para páginas completas
=============================================================
"""

import io
import easyocr
import numpy as np
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pydantic import BaseModel
from PIL import Image
from typing import Optional, List
import os

# =============================================================
# CONFIGURACION
# =============================================================

app = FastAPI(
    title="EasyOCR API",
    description="Reconocimiento de texto rápido con EasyOCR",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# =============================================================
# MODELOS DE RESPUESTA
# =============================================================

class LineDetail(BaseModel):
    texto: str
    confianza: float

class OCRResponse(BaseModel):
    exito: bool
    texto: str
    confianza: float
    lineas: List[LineDetail]
    mensaje: Optional[str] = None

# =============================================================
# GESTOR DE EASYOCR
# =============================================================

class EasyOCRManager:
    def __init__(self):
        self._reader = None

    @property
    def reader(self):
        if self._reader is None:
            print("=" * 50)
            print("Cargando EasyOCR (español + inglés)...")
            print("=" * 50)
            self._reader = easyocr.Reader(
                ['es', 'en'],
                gpu=False,
                verbose=False
            )
            print("EasyOCR listo!")
        return self._reader

    def recognize(self, image: Image.Image) -> tuple:
        """Reconoce texto en una imagen"""

        # Convertir a RGB
        if image.mode != 'RGB':
            image = image.convert('RGB')

        # Redimensionar si es muy grande
        max_size = 2048
        if max(image.size) > max_size:
            ratio = max_size / max(image.size)
            new_size = (int(image.size[0] * ratio), int(image.size[1] * ratio))
            image = image.resize(new_size, Image.Resampling.LANCZOS)

        # Convertir a numpy array
        image_np = np.array(image)

        # Reconocer
        resultados = self.reader.readtext(image_np)

        if not resultados:
            return "", 0.0, []

        textos = []
        confianzas = []
        lineas = []

        for bbox, texto, conf in resultados:
            texto = texto.strip()
            if texto and conf >= 0.3:  # Filtrar baja confianza
                textos.append(texto)
                confianzas.append(conf)
                lineas.append({
                    "texto": texto,
                    "confianza": round(conf, 3)
                })

        texto_completo = ' '.join(textos)
        confianza_promedio = sum(confianzas) / len(confianzas) if confianzas else 0.0

        return texto_completo, confianza_promedio, lineas

# Instancia global
ocr = EasyOCRManager()

# =============================================================
# ENDPOINTS
# =============================================================

@app.get("/")
async def inicio():
    return {
        "nombre": "EasyOCR API",
        "version": "1.0.0",
        "descripcion": "Reconocimiento de texto rápido",
        "modelo": "EasyOCR (español + inglés)",
        "velocidad": "~2-5 segundos por imagen",
        "endpoints": {
            "GET /": "Esta información",
            "GET /health": "Estado del servicio",
            "GET /docs": "Documentación Swagger",
            "POST /recognize": "Reconocer texto en imagen"
        }
    }

@app.get("/health")
async def health():
    return {"status": "ok", "modelo": "EasyOCR"}

# Servir index.html si existe
@app.get("/app")
async def serve_app():
    if os.path.exists("index.html"):
        return FileResponse("index.html")
    return {"error": "index.html no encontrado"}

@app.post("/recognize", response_model=OCRResponse)
async def recognize(file: UploadFile = File(...)):
    """
    Reconoce texto en una imagen usando EasyOCR.

    Rápido: ~2-5 segundos por imagen
    Soporta: Español e Inglés
    """
    if not file.content_type or not file.content_type.startswith('image/'):
        raise HTTPException(status_code=400, detail="Debe ser una imagen")

    try:
        contents = await file.read()
        image = Image.open(io.BytesIO(contents))

        texto, confianza, lineas = ocr.recognize(image)

        if texto:
            return OCRResponse(
                exito=True,
                texto=texto,
                confianza=round(confianza, 3),
                lineas=[LineDetail(**l) for l in lineas],
                mensaje=f"Se reconocieron {len(lineas)} elementos"
            )
        else:
            return OCRResponse(
                exito=False,
                texto="",
                confianza=0.0,
                lineas=[],
                mensaje="No se detectó texto"
            )

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# =============================================================
# MAIN
# =============================================================

if __name__ == "__main__":
    import uvicorn
    print("\n" + "=" * 50)
    print("  EasyOCR API")
    print("  http://localhost:7860")
    print("  Docs: http://localhost:7860/docs")
    print("=" * 50 + "\n")
    uvicorn.run(app, host="0.0.0.0", port=7860)