package services import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "time" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" ) var ocrHTTPClient = &http.Client{Timeout: 30 * time.Second} // ExtraerTextoOCR manda una imagen al servicio propio de OCR y devuelve el // texto extraído. mimeType ej: "image/png", "image/jpeg". // // agenteID identifica a quién cobrarle la imagen procesada; 0 = no medir, que // es lo que pasa el botón "Probar" del panel de staff (no es de ningún cliente). func ExtraerTextoOCR(agenteID uint, imagenBytes []byte, mimeType string) (string, error) { cfg, err := models.GetOcrConfig() if err != nil { return "", fmt.Errorf("el servicio de OCR no está configurado (Integraciones → OCR)") } body, err := json.Marshal(map[string]string{ "image_base64": base64.StdEncoding.EncodeToString(imagenBytes), "mime_type": mimeType, }) if err != nil { return "", err } req, err := http.NewRequest(http.MethodPost, cfg.BaseURL, bytes.NewReader(body)) if err != nil { return "", err } req.Header.Set("Authorization", "Bearer "+cfg.Token) req.Header.Set("Content-Type", "application/json") resp, err := ocrHTTPClient.Do(req) if err != nil { return "", fmt.Errorf("no se pudo contactar el servicio de OCR: %w", err) } defer resp.Body.Close() raw, _ := io.ReadAll(io.LimitReader(resp.Body, 2*1024*1024)) if resp.StatusCode < 200 || resp.StatusCode >= 300 { return "", fmt.Errorf("el servicio de OCR respondió %d: %s", resp.StatusCode, string(raw)) } var out struct { Success bool `json:"success"` Text string `json:"text"` Error string `json:"error"` } if err := json.Unmarshal(raw, &out); err != nil { return "", fmt.Errorf("respuesta inesperada del servicio de OCR: %s", string(raw)) } if !out.Success { msg := out.Error if msg == "" { msg = "el servicio de OCR no pudo procesar la imagen" } return "", fmt.Errorf("%s", msg) } RegistrarUso(agenteID, models.UsoTipoOCR, 1, "imagen") return out.Text, nil }