Grabar y emular un ratón en linux

Hoy me tocó un trabajo muy ingrato, tenía que reenviar de una cuenta de correo a otra todos los correos recibidos en dos meses. El correo estaba gestionado en una cuenta de outlook y ya tenía como 2000 correos acumulados. En principio suponía que sería sencillo, selecciono todos y reenvio… Pues no, outlook no te deja hacerlo así. El origen de la tarea era porque una regla de reenvío, que lo hace automáticamente, había estado deshabilitada un tiempo y, desafortunadamente, tampoco hay forma de hacerla correr solo para un conjunto determinado de correos, o todos, o los que entran, nada de reglas «personalizadas».

Conseguí crear una acción rápida para enviar el correo y mover el mensaje a la carpeta de procesados (para tenerlos ordenaditos), pero las acciones de outlook no te mandan los mensajes automáticamente sino que te generan un borrador con el destinatario y tu tienes que dar al botón enviar. Así que ahora tenía que dar dos clicks por cada mensaje… Solo son 2000!! ESto podía llevarme muuuucho tiempo.

¿Probamos a bajarlos por imap o algo? Pueeee no, microsoft se ha puesto muy borde con la autenticación del correo y no iba a ser sencillo, así que, para no tirarme toda una mañana (o todo un día) haciendo clicks y creandome un tunel carpiano inmenso tiré de google y encontré un repositorio de alguien que te permite grabar lo que haces con el ratón y repetirlo (aunque era en el navegador el uso de selenium me daba mucha pereza). En concreto el repositorio es este:

https://github.com/RMPR/atbswp

Y las instrucciones «rápidas» para instalarlo en un ubuntu serían estas:

sudo apt install git python3-dev python3-tk python3-setuptools python3-wheel python3-pip python3-wxgtk4.0
git clone https://github.com/RMPR/atbswp.git && cd atbswp
python3 -m pip install pyautogui pynput --user
python3 atbswp/atbswp.py

Una vez instalado y lanzado solo hay que grabar la secuencia que queramos (empezamos dando al botón de grabar o al f9 y terminamos igualmente). Esta secuencia se puede guardar en un archivo para ejecutarla posteriormente (o editarla a mano como hice yo) y luego se puede cargar y ejecutar un número determinado de veces.

Dicho y hecho, registro mis dos clicks y digo que se ejecuten 2000 veces… Ahora solo queda esperar a que termine!

Eso si, el ordenador no puedo usarlo mientras está haciendo mi trabajo… Bueno, será por ordenadores… Me ha dado tiempo a escribir esta entrada y todo mientras redirijo correos.

Japón es otro mundo

Hoy no voy a escribir de temas técnicos, que últimamente tengo mucha deuda técnica que pagar y estoy un poco despistado con los siguientes pasos, así que, aprovechando que me he ido a Japón unos días de vacaciones para contaros las cosas que me han sorprendido de este país.

La puntualidad de los transportes

Si en Japón un tren dice que sale a las 12:13 saldrá a las 12:13, no hay más, cualquier retraso es avisado en todas partes y, realmente, hay muy pocos y están muy justificados. Sea tren, metro o avión la puntualidad de los Japoneses con los transportes es algo que no creí que fuese real hasta que lo comprobé por mi mismo. Si abres google maps y le preguntas cómo llegar a algún sitio en transporte público verás las horas de salida de cada tren con una exactitud pasmosa. Supongo que eso es algo que se puede conseguir teniendo el mantenimiento adecuado del sistema y con disciplina. Algo que deberíamos copiar los demás.

La limpieza en las calles

Creí que era un mito, pero no, no hay papeleras en las calles de las ciudades que he visitado. Aún así, estas están completamente limpias, ni colillas (está prohibido fumar en la calle), ni papeles, ni nada de nada. Hay unas pocas papeleras para botellas y latas al lado de algunas máquinas de vending o, en otro caso, en las tiendas de conveniencia (aunque queda un poco raro entrar en una tienda solo para tirar basura). No me puedo explicar cómo es posible que los japoneses sean tan respetuosos con el tema de las basuras (algunos turistas no lo son tanto, pero son pocos)

El uso de las bicicletas

Este no es un punto positivo, más bien lo contrario, aunque en Japón se usan mucho las bicicletas, parece que los carriles bici no tienen mucho éxito y hay mucha gente por las aceras circulando en bicicletas y es muy difícil esquivarlas si te vienen por detrás. Quizá no teníamos muy interiorizadas las reglas para circular por las aceras (ellos circulan por la izquierda y se ponen en ese lado de las escaleras igualmente), pero es un poco caos cuando hay varias bicicletas a distintas velocidades circulando por tu misma acera. Es loable que usen este medio de transporte tan a menudo, pero hay que mejorar un poco la forma en que lo hacen.

El silencio en los transportes

En España ir en metro supone meterse en un guirigay de sonidos variados, gente hablando, móviles sonando, pedigüeños molestando. En Japón NADIE habla en el transporte público, menos aún en los días de diario. Si alguien está hablando será un turista despistado o que estamos en día festivo y estamos en un tren hacia un destino turístico. La verdad es que se agradece estar en medio de una multitud y no oir ni una mosca.

Las excursiones escolares

Si, igual es una tontería, pero cuando estuvimos en Nara y en Kyoto vimos muchísimos escolares que iban de excursión sin supervisión (o al menos ninguna que nosotros viésemos). Chicos de 12 y menos años visitando los sitios turísticos a su bola y volviendo a los autobuses sin que nadie tuviese que estar detrás de ellos diciéndoles lo que tenían que ver o no. Es cierto que los Japoneses hacen que sus hijos vayan solos al colegio y que tengas una autonomía propia desde muy jóvenes, pero es algo que me choca mucho con lo que se ve en nuestro país.

Todavía me quedan muchas cosas que contar sobre esto, pero como aperitivo lo dejo aquí, no sea que se me olvide… Iremos actualizando.

De puertas traseras y software libre

Es casi imposible que no hayas oido hablar del backdoor xz, no es que yo pueda darte más información sobre el tema, os dejo un video de alguien que os cuenta el caso completo como si de un episodio de serie negra se tratase:

El caso es que, alguien durante tres años ha ido infiltrándose en un repositorio de un elemento pequeño pero crítico de software libre llamado xz, de tal manera que consiguió, no solo quedarse como mantenedor de ese repositorio sino que fue introduciendo, poco a poco, una puerta trasera que permitía el acceso remoto (todavía hay que ver el payload real lo que llegaba a hacer) y conseguir que ese backdoor se distribuyese en algunas de las más importantes distribuciones.

Por suerte, o mejor dicho, por la misma estructura del software libre, esta versión no pasó de las versiones inestables de las distribuciones y se descubrió el pastel porque una persona notó que algo iba más lento de lo que debía después de la actualización. Esta persona (Andres Freund) no se paró en medir el tiempo de respuesta sino que terminó encontrando la causa subyacente y la puerta trasera que habían metido (aquí el aviso que dió a la comunidad) y, obviamente, la reacción de los mantenedores de la distribución, e incluso del antiguo mantenedor del repositorio fue inmediata y reliminó todas las trazas del código dañino.

Hay varias cosas que podemos destacar, pero yo me quedo con un par de ellas:

  1. La dependencia que tenemos de código que han escrito terceros y que pueden estar bien mantenidos o no (dependiendo del ánimo de esa persona o de sus circunstancias personales)
  2. La potencia del ecosistema open source para descubrir y arreglar este tipo de problemas. Todos los sistemas operativos actuales, desde mac os hasta windows usan componentes externos, no hay ninguno 100% original y tampoco es que se pueda saber qué es lo que usan exactamente. Si hay un backdoor en windows o en macos nos lo tendremos que comer con patatas porque nadie puede mirar lo que hay dentro.

Estoy seguro de que esta forma de actuar, por muy inteligente y paciente que sea, no deja de ser un ataque en toda regla con unas finalidades seguramente malvadas (crear una botnet inmensa, por ejemplo) y no creo que sepamos realmente quien está detrás de ello y, posiblemente, nos de para una docuserie de Netflix un día de estos.

En fin, no ha pasado nada, todo está en orden de nuevo y lo malo es que nos deja un regusto amargo y hace bajar un peldaño la confianza que teníamos en el ecosistema (pero no mucho, oye, que seguimos estando a salvo).

¿La era de la Inteligencia artificial?

Tengo que reconocer que con el advenimiento de chatGPT y las muestras de la IA generativa en campos como la programación de un tiempo a esta parte las expectativas se han disparado con respecto a lo que se puede esperar de una Inteligencia Artificial. Sin embargo, no es oro todo lo que reluce.

La disciplina de Inteligencia Artificial existe desde hace muchísimos años, yo mismo, como estudiante de mi facultad fui miembro del Laboratorio de Inteligencia Artificial desde el año 1989 hasta que salí del mismo (esa es una historia para contar en otro momento) y me dediqué a otros proyectos de IA como la traducción automática. Pero la IA es anterior a estas fechas incluso. La verdad es que el avance «real» de la IA no ha sido expectacular estos años pasados excepto en la imaginación de algunos autores de ciencia ficción.

¿Porqué, entonces, se ha notado un avance tan importante estos últimos años? Bueno, lo que yo os puedo decir es que no toda la IA ha avanzado por igual, la que ahora mismo disfutamos es la IA generativa basada en aprendizaje profundo «Deep Learning». Para que se entienda, se trata de un sistema que «aprende» en base a miles de millones de muestras a generar «algo», una imagen, un texto, una respuesta ante una entrada determinada. Y el problema está en que al utilizar esa IA simplemente estamos recombinando los elementos de su entrenamiento de manera que sea más o menos adecuado a la pregunta o solicitud de entrada, no hay lógica, no hay algoritmo, es simple aprendizaje.

Si tu le preguntas algo a chatGPT no se desencadenan procedimientos lógicos que luego se puedan auditar, lo que se produce es una generación de lo que más probablemente, según los documentos que ya aprendió, se parezca a una respuesta a esa pregunta. Lo más parecido a un papagayo al que se le han enseñado miles de frases, te dará una respuesta tenga ésta sentido o no lo tenga.

De hecho, uno de los efectos más curiosos de las IAs generativas es que se inventan cosas – «alucinaciones» -, y no hay forma de que sepan si es cierto o no lo que están contando, por lo que es complicado, por no decir imposible, fiarse al 100% de lo que podamos obtener de una IA de este estilo. A diferencia de las imágenes que ilustran esta entrada, que han sido generadas por IA y podemos verlas como una simple muestra más o menos estética, si hacemos caso de lo que nos recomienda chatGPT, Gemini o cualquier otra AI generativa estaremos haciendo caso a un papagayo con mucho entrenamiento.

Este resurgir de la IA ha sido, básicamente, consecuencia de la acumulación de cientos de miles de millones de datos proporcionados por los usuarios de internet, unos conscientemente y otros inconscientemente en pago por el uso de alguna red social o alguna herramienta «gratuita». De hecho, la disponibilidad de estos conjuntos de entrenamiento tan inmensamente grande es lo único que ha permitido la ilusión de disponer de un asistente inteligente de verdad y, repito, es una ilusión. Nunca te fíes de quien no puede explicarte porqué ha hecho o dicho algo… Y las IAs generativas no pueden.

¿Hay que descartar entonces el uso de estas IAs? No, en ningún caso, disponer de una herramienta entrenada con datos que nos son útiles (como todos los códigos de github que su copilot ha usado en su entrenamiento) nos pueden ahorrar mucho tiempo en disponer de versiones preliminares o códigos sin refinar. Pero siempre necesitaremos alguien para refinar los resultados de cualquier IA generativa. Simplemente porque la IA no sabe realmente qué es lo que está diciendo (y nunca lo sabrá). El hecho de que haya gente planeándose reemplazar personas humanas por IAs (o incluyo que ya lo han hecho) demuestra que hay trabajos de bajo valor añadido que no necesitan siquiera razonar correctamente para ser desempeñados, esos trabajos si que pueden ser reemplazados, pero igual es que la necesidad de éstos ya era algo anecdótico.

Pasar a producción un API en python con flask / connexion

Hacer un servicio que sirva un API en python es muy, muy sencillo usando flask o connexion. Mi método favorito de hoy (esto cambia día a día) es usar connexion que nos permite crear un servidor teniendo su definición en un archivo openapi con simplemente tres líneas de código:

app = connexion.App(__name__,specification_dir='./')
CORS(app.app)
app.add_api('openapi.yml')
app.run(port=8080)

Con estas cuatro líneas de código (además de los imports correspondientes) ya tendríamos un servidor web en el puerto 8080 de la máquina. Luego basta con tener en el openapi.yml definido el nombre de las operationId e implementarlas adecuadamente… Me tienta, pero en este momento no voy a hacer un tutorial sobre connexion o sobre cómo generar un proyecto python usable. Para esta entrada supongamos que ya tenemos el servidor implementado y corriendo… Veremos que cuando lo arrancamos nos muestra este mensaje:

 * Serving Flask app 'app'
 * Debug mode: off
2024-01-25 20:57:13,203 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://172.18.0.20:8080
2024-01-25 20:57:13,204 - werkzeug - INFO - Press CTRL+C to quit

Si nos fijamos nos está advirtiendo de que el servidor que está usando es el propio de Flask y no es muy adecuado para entornos de producción. ¿Qué significa esto? Que si recibe muchas peticiones el tiempo de proceso de las mismas va a ser muy alto. El mismo mensaje nos recomienda usar un servidor WSGI para entornos de producción.

De hecho, si estás ejecutando una versión más moderna de connexion te aparecerá este mensaje en su lugar:

2024-01-25 22:05:31,351 - connexion.middleware.main - WARNING - `ConnexionMiddleware.run` is optimized for development. For production, run using a dedicated ASGI server.

Que es lo mismo pero con ASGI en lugar de WSGI. La receta para ejecutarlo mas en «producción» en este caso sería instalar gunicorn y lanzarlo con un tipo de worker ASGI (uvicorn en este caso) teniendo en cuenta que app está definido dentro del archivo app.py:.

pip install gunicorn
gunicorn -k uvicorn.workers.UvicornWorker --bind "0.0.0.0:8080" app:app

Con eso ya lanzamos un proceso, si queremos lanzar más lo podemos hacer con el parámetro -w poniendo, por ejemplo:

gunicorn -k uvicorn.workers.UvicornWorker -w 4 --bind "0.0.0.0:8080" app:app

Con esto ya se lanza 4 procesos para dar servicio al API… Esto debería mejorarlo.

Y una cosa más… Si tenéis algún proceso en la aplicación que no deba replicarse con cada worker (un scheduler por ejemplo), tenéis que lanzar gunicorn con el parámetro --preload para que se ejecute solo una instancia de la aplicación (de todo lo que no dependa de las peticiones)