Clasificación de imágenes con Worker Cloudflare

Hoy estamos experimentando con una característica útil de AI que se refiere a la clasificación de imágenes, es decir, un modelo AI creado específicamente para devolver una explicación escrita de una imagen a través de la URL de la imagen. ¿Para qué puede ser útil? Como primera aplicación, para saber lo que hay dentro de una imagen sin siquiera abrirla; esto abre las puertas a una serie de otras aplicaciones tales como reconocer abuso o comportamiento inapropiado escaneando una lista de transcripciones de texto de imágenes. También es útil para tener automáticamente una descripción de la imagen y guardarla en alguna base de datos. ¿Qué necesitamos?
1) Una cuenta en Cloudflare (incluso gratis)
2) A trabajador dentro de su Cuenta de Cloudflare (incluso gratis)
En los trabajadores de Cloudflare ya hay un script preestablecido para generar transcripciones de texto de imágenes, pero los scripts preestablecidos no están en absoluto seguros de usar en un entorno de producción; en este post veremos cómo podemos personalizar el script para hacerlo más seguro y utilizarlo en un entorno PHP.

¿Qué queremos hacer? El objetivo principal es crear un script que, a partir de una URL de imagen enviada con el método POST, devuelve la descripción de la imagen a través del modelo de inteligencia artificial llamado “resnet-50”. ResNet es una red neural muy profunda (CNN), compuesta de 152 capas, que con la ayuda de una técnica conocida como conexión de salto ha allanado el camino para redes residuales (red residual).

¿Qué necesitamos generar? Para la solicitud a nuestro trabajador vamos a utilizar un archivo PHP; mientras que para que el script se inserte en nuestro trabajador vamos a utilizar uno personalizable que es más seguro que el predeterminado.

Worker script

por defecto de exportación {}
async fetch(request, env) {
// Compruebe si el encabezado de Autorización contiene una ficha válida
const authHeader = request.headers.get("Authorization");
const valid Token = "YOUR_AUTHENTICATION_TOKEN";

si (!authHeader ¦ `Bearer ${validToken}`) {}
// Si el token falta o es inválido, devuelve un error no autorizado 401
Retorno de la nueva respuesta
JSON.stringify({ error: "Invalid or missing autation token." }),
{ status: 401, headers: { "Content-Type": "application/json" } }
);
}

// Proceso sólo solicitudes válidas de POST
si (Solicitud. método !== "POST") {
// Si el método no es POST, devuelve un método 405 No se permite error
devolver nuevo Respuesta("Invalid request method. Use POST con los datos necesarios.", {}
status: 405,
headers: { "Content-Type": "text/plain" },
});
}

♪
// Validar el tipo de contenido de la solicitud
const content Tipo = petición.headers.get("Content-Type")
si (!contentType.includes("application/json") {
// Si el tipo de contenido no es JSON, devuelve un error de 400 Bad Request
Retorno de la nueva respuesta
JSON.stringify({ error: "Invalid Content-Type. Solicitud esperada / json." }),
{ status: 400, headers: { "Content-Type": "application/json" } }
);
}

// Parse el cuerpo de la solicitud
const body = await request.text();
si (!body) {
// Si el cuerpo de solicitud está vacío, devuelva un error de 400 Bad Request
Retorno de la nueva respuesta
JSON.stringify({ error: "El cuerpo de solicitud está vacío". )
{ status: 400, headers: { "Content-Type": "application/json" } }
);
}

const { image Url = JSON.parse(body);
si (!imageUrl) {
// Si la URL de la imagen no se proporciona en el cuerpo, devuelve un error de 400 Bad Request
Retorno de la nueva respuesta
JSON.stringify({ error: "No hay URL de la imagen proporcionada." }),
{ status: 400, headers: { "Content-Type": "application/json" } }
);
}

// Obtener la imagen de la URL proporcionada
const imageResponse = await fetch(imageUrl);
blob const = esperar imagenResponse.arrayBuffer();

// Preparar las entradas para el modelo AI
const inputs = {}
imagen: [...nuevo Uint8Array(blob)],
};

// Ejecutar el modelo AI y obtener la respuesta
const response = await env.AI.run("@cf/microsoft/resnet-50", inputs);

// Regresar la respuesta del modelo AI
Retorno de la nueva respuesta
JSON.stringify({ response }),
{ headers: { 'Content-Type': "application/json" }
);
Atrapado (error) {
// Maneja cualquier error inesperado y devuelve un error de 500 servidores internos
Retorno de la nueva respuesta
JSON.stringify({ error: error.message }),
{ status: 500, headers: { "Content-Type": "application/json" } }
);
}
}
};

¿Qué considerar al personalizar este script? La constante válido Token debe contener su ficha personalizada para pasar en el momento de la solicitud, insertar una contraseña y luego recordarla para volver a introducirla en el archivo PHP más abajo; si las fichas no son iguales el script devolverá un error 401 y guardará más trabajo de CPU (esta constante se puede cambiar pero debe ser el mismo en el script PHP) ; además, si la solicitud no viene de un método POST, el script devolverá un error 405 utilizado también Si todo es correcto, entonces podemos seguir enviando el archivo de imagen a la inteligencia artificial, que devolverá su descripción en formato JSON listo para ser capturados por el script PHP que vamos a construir.

PHP script

Vamos a llamar a este script imageai.php y guardarlo en un directorio protegido

Identificado?php
// URL de tu Trabajador Cloudflare
$cloudflare Url = "https://yoururl.workers.dev/";
$authToken = "YOUR_AUTHENTICATION_TOKEN"; // Authentication token para que coincida con el Worker

($_SERVER['REQUEST_METHOD] === 'POST') {
$imageUrl = $_POST['imageUrl'];

si (vacío($imageUrl)) {}
// Compruebe si se proporciona la URL de la imagen; si no, devuelva un error
echo json_encode(['error' = "Image URL is missing.']);
salida;
}

// Verificar si la URL apunta a una imagen real comprobando su encabezado Tipo de Contenido
$headers = get_headers($imageUrl, 1);
si (!isset($headers['Content-Type'])
// Si la URL no apunta a una imagen, devuelve un error
eco json_encode(['error' = "La URL no contiene una imagen válida".]
salida;
}

// Prepare la carga útil JSON para la solicitud
$data = json_encode(['imageUrl' = $imageUrl]);

// Establecer las opciones de solicitud, incluyendo el encabezado Autorización con el token
$options = [
"http" = título [
"header" = "Content-Type: application/json\r\n" .
"Authorization: Bearer $authToken\r\n",
// Incluir la ficha en el encabezado de Autorización
'Method' = 'POST',
'contento' = confianza $data,
]
];

// Enviar la solicitud al Trabajador y obtener la respuesta
$context = stream_context_create($options);
$response = file_get_contents($cloudflare Url, false, $context);

si (respuesta ==== FALSE) {
// Si el Trabajador es inalcanzable, devuelve un error
eco json_encode(['error] "Incapaz de contactar con el Trabajador".]
salida;
}

// Decodificar la respuesta JSON del Trabajador
$decodedResponse = json_decode(respuesta, verdadera);
si ($decodedResponse === null) {
// Si la respuesta no es válida JSON, devuelve un error
eco json_encode(['error] "La respuesta no es válida JSON".]
salida;
}

// Producto de la respuesta decodificada
eco json_encode($decodedResponse);
}
?

¿Qué considerar al personalizar este script? La variable $authToken contiene las fichas de autenticación que establecemos en el script de trabajo (antes); el valor debe ser el mismo en ambos scripts. La variable $cloudflare Url contiene toda la URL donde se guarda el script del trabajador (previamente guardado), generalmente comienza con https:// y termina con los trabajadores. dev pero también puede asociar un subdominio personalizado (a su preferencia). El script se puede llamar de un
en html y debe pasar la imagen url de un campo con id “imageUrl”, obviamente también se puede llamar a través de POST de otro script en javascript (como usted lo prefiere); el script PHP en este punto comprueba que el url pasado a través de POST está allí y comprobar si es en realidad una imagen; una vez que los cheques han pasado se llama el script del trabajador, comprueba si el servicio está disponible y accesible, y el formato J.

Forma HTML

¡Seguido! DOCTYPE html
"Lang="en"
■head
################################################################################################################################################################################################################################################################
■meta name="viewport" content="width=device-width, initial-scale=1.0"
< > > > >
■style
cuerpo
fuente-familia: Arial, sans-serif;
márgen: 20px;
padding: 0;
color de fondo: #f4f4f9;
color: #333;
}
formulario {
Ancho máximo: 400px;
margen: 0 auto;
padding: 20px;
Fondo: #fff;
frontera: 1px solid #ddd;
frontera-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
entrada [tipo="text"] {
ancho: 100%;
padding: 10px;
márgen: 10px 0;
frontera: 1 px sólido #ccc;
frontera-radius: 3px;
}
botón {}
ancho: 100%;
padding: 10px;
color de fondo: #007bff;
color: blanco;
frontera: ninguna;
frontera-radius: 3px;
cursor: puntero;
}
botón: más allá {
color de fondo: #0056b3;
}
.descripción {
margen-top: 20px;
font-size: 16px;
text-align: centro;
padding: 10px;
frontera-radius: 5px;
}
.descripción. éxito {
color de fondo: #d4edda;
color: #155724;
}
.description.error {}
color de fondo: #f8d7da;
color: #721c24;
}
> >
Identificado/cabeza
♪ ♪♪
> > > >
Enter la URL de una imagen para clasificarla:

id="classificationForm" método="POST"
id="imageUrl" placeholder="Enter image URL" requerido
"Escritor" Clasificar imagen realizada/button
■/formulado
Identificado
id="descripciónContainer" class="description" style="display: none;"

Identificado
document.getElementById('classificationForm').addEventListener('submit', async function (event) {
event.preventDefault(); // Prevent form submission and page reload

imagen const Url = document.getElementById('imageUrl').value;
const descriptionContainer = document.getElementById('descriptionContainer');

♪
// Enviar la URL de la imagen vía POST al script PHP
const response = await fetch('imageai.php', {
método: 'POST',
encabezados: {}
'Content-Type': 'application/x-www-form-urlencoded',
}
cuerpo: 'imageUrl='+encodeURIComponent(imageUrl)
});

const result = await response.json();

si (response.ok) {
// Mostrar la descripción recibida del script PHP
descripciónContainer.textContent = 'Descripción: '+result.response;
descripciónContainer.className = "el éxito de la descripción";
Si no
// Mostrar un mensaje de error
descripciónContainer.textContent = 'Error: '+result.error+' Se produjo un error inesperado".
descripciónContainer.className = 'error de descripción';
}

descripciónContainer.style.display = 'block'; // Hacer visible el contenedor
Atrapado (error) {
// Errores de red o servidor
descripciónContainer.textContent = Error: '+error.message;
descripciónContainer.className = 'error de descripción';
descripciónContainer.style.display = 'block';
}
});
■/script título
Identificado/cuerpo
Identificado/html

Conclusión

Este script se puede utilizar a través de un formulario HTML (como se presenta aquí) o incluso a través de un script javascript que se encargará de enviar la solicitud POST, pero también se puede utilizar completamente a través de PHP tal vez asegurándose de que el resultado se guarda directamente en una base de datos para ser devuelto en un momento posterior (cuando se solicita). La aplicación puede tener diferentes funciones dependiendo de la necesidad; recuerde que siempre es mejor hacer menos solicitudes complicadas a los trabajadores porque, aunque tienen altos límites incluso con una cuenta gratuita, todavía tienen límites. Es buena práctica guardar la información recibida en una base de datos, y para la misma url (o la misma imagen) y recuperar la información a través de la base de datos (caching) para no obstruir al trabajador con demasiadas solicitudes. Los controles implementados (token y host verification) se utilizan precisamente para no enviar demasiadas solicitudes que podrían llegar a los límites de los trabajadores. Además, en Cloudflare, también puede establecer su firewall de aplicación (WAF) para asegurarse de que las solicitudes a ese trabajador deben venir del host especificado (para no aumentar el contador de límites de trabajo). Recuerde que para un mejor rendimiento el modelo resnet-50 espera el tamaño de la imagen 224×224 píxeles, por lo que se recomienda cambiar el tamaño de la imagen a esas dimensiones antes de enviarla.