Guía para desarrollo de plugins
Guía para desarrollo de plugins
Sección titulada «Guía para desarrollo de plugins»Nuestro compromiso con el desarrollo de ArchiHUB como proyecto de código abierto va más allá de la creación de la herramienta con licencia de uso libre. También queremos fomentar las contribuciones de los usuarios de ArchiHUB, permitiendo que cualquier persona pueda campliar sus funcionalidades con el desarrollo de plugins. En esta sección, te guiaremos a través del proceso de creación de un plugin para ArchiHUB.
¿Qué es un plugin?
Sección titulada «¿Qué es un plugin?»Un plugin es un módulo adicional que se puede integrar en ArchiHUB para ampliar sus funcionalidades. Los plugins pueden ser utilizados para agregar nuevas características o incluso integrar ArchiHUB con otras herramientas y servicios.
Como ejemplo, tenemos el plugin para transcripción de audio y video que permite a los usuarios transcribir automáticamente el contenido de sus archivos multimedia usando el modelo Whisper de OpenAI.

En esta guía vamos a desarrollar un plugin que permite la integración de ArchiHUB con la API de OpenAI. Este plugin permitirá a los usuarios de ArchiHUB modificar títulos de recursos usando inteligencia artificial.
Estructura de un plugin
Sección titulada «Estructura de un plugin»Como punto de partida, usaremos la plantilla de plugin que se encuentra en el repositorio de ArchiHUB. Esta plantilla contiene la estructura básica de un plugin y algunos ejemplos de cómo se pueden implementar diferentes funcionalidades. Para acceder a la plantilla, puedes clonar el repositorio del backend y buscar el archivo Plugin.py en la carpeta app/utils/templates/.
Los plugins en ArchiHUB siempre contienen las siguientes partes:
- Información estructurada del plugin: contiene la información básica del plugin. Esta se define en formato JSON y se encuentra al final de la plantilla del plugin.
- Endpoints: contiene los endpoints que se exponen para interactuar con el plugin o la herramienta en general. Estos se definen en la función
add_routesdisponible en la pl antilla del plugin. - Tareas: contiene las tareas que se ejecutan al procesar archivos. Estas tareas se definen en la función
bulkdisponible en la plantilla del plugin.
Creación de un plugin
Sección titulada «Creación de un plugin»Como primer paso, debemos definir una funcionalidad y un nombre para el plugin. En este caso, vamos a crear un plugin que permite modificar títulos de recursos usando la API de OpenAI. El nombre del plugin será titleModifier. A continuación, se describen los pasos para crear el plugin:
- Crea la carpeta del plugin: crea una carpeta con el nombre del plugin en la carpeta
pluginsdel aplicativo. En este caso, la carpeta se llamarátitleModifier. - Crea el archivo del plugin: dentro de la carpeta de los plugins siempre se debe crear un archivo
__init__.py. En este caso, crea el archivo__init__.pydentro de la carpetatitleModifiercomo copia de la plantilla del plugin. - Define el logo del plugin: el logo del plugin se debe guardar en la carpeta
staticdentro de la carpeta del plugin con el nombreimage.png. En este caso, guarda el logo del plugin en la carpetatitleModifier/static/image.png. - Define las dependencias del plugin: si el plugin requiere de dependencias adicionales, estas se deben definir en el archivo
requirements.txtdentro de la carpeta del plugin. En este caso, el plugin requiere de la libreríaopenai, por lo que se debe crear el archivorequirements.txtdentro de la carpetatitleModifiercon el siguiente contenido:
openaiEs importante que siempre se deje un salto de línea al final del archivo requirements.txt para evitar errores en la instalación de las dependencias con docker.
-
Define las variables de entorno del plugin: si el plugin requiere de variables de entorno adicionales, estas se deben definir en un archivo
.enven la carpeta del plugin. En este caso, el plugin requiere de la variableOPENAI_API_KEYcon la llave generada en la cuenta de OpenAI. Para ello, abre el archivo.enven cualquier editor de texto y asigna la llave generada. -
Modifica el archivo
__init__.py: en el archivo__init__.pyse debe escribir el código del plugin. Para iniciar, se modifica la información del plugin. Esta información se encuentra al final del archivo__init__.pyy se debe modificar con la siguiente información:
plugin_info = { 'name': 'Plugin para modificar títulos de recursos usando la API de OpenAI', 'description': 'Plugin para modificar títulos de recursos usando la API de OpenAI', 'version': '0.1', 'author': 'BITSOL SAS', 'type': ['bulk'], 'settings': { 'settings_bulk': [ { 'type': 'instructions', 'title': 'Instrucciones', 'text': 'Este plugin permite modificar títulos de recursos usando la API de OpenAI. Para usarlo, selecciona los archivos que quieres modificar y configura las opciones del plugin.', }, { 'type': 'select', 'label': 'Modelo', 'id': 'model', 'default': 'gpt-3.5-turbo', 'options': [ {'value': 'gpt-3.5-turbo', 'label': 'GPT 3.5 Turbo'}, {'value': 'gpt-4o', 'label': 'GPT 4o'}, {'value': 'gpt-4o-mini', 'label': 'GPT 4o Mini'}, {'value': 'gpt-4o-turbo', 'label': 'GPT 4o Turbo'} ], 'required': False, }, { 'type': 'text', 'label': 'Instrucciones', 'id': 'instructions', 'default': 'Tengo una herramienta de gestión documental con varios recursos y quiero que me ayudes a reescribir el título de esos recursos para que sean más atractivos y llamen la atención de los usuarios usando pocas palabras. Además, debe estar en español.', 'required': True }, { 'type': 'text', 'label': 'Comando para GPT', 'id': 'input', 'default': 'Por favor, reescribe el siguiente título de un recurso:', 'required': True } ] }}Luego deberás definir los endpoints y las tareas del plugin. Para ello, se debe modificar la función add_routes y la función bulk respectivamente. En la función add_routes, se deben definir los endpoints que el plugin expondrá para su uso. Por defecto, ya se encuentra configurado el endpoint bulk para el llamado de la función bulk. En este caso, se debe modificar la función add_routes para que quede de la siguiente manera:
def add_routes(self): @self.route('/bulk', methods=['POST']) @jwt_required() def process_files(): current_user = get_jwt_identity() body = request.get_json()
if 'post_type' not in body: return {'msg': 'No se especificó el tipo de contenido'}, 400
if not self.has_role('admin', current_user) and not self.has_role('processing', current_user): return {'msg': 'No tiene permisos suficientes'}, 401
task = self.bulk.delay(body, current_user) self.add_task_to_user(task.id, 'titleModifier.bulk', current_user, 'msg')
return {'msg': 'Se agregó la tarea a la fila de procesamientos'}, 201Nótese que en este caso se está validando que el usuario tenga permisos para ejecutar el plugin. Esto es importante ya que el plugin va a modificar títulos de recursos y no todos los usuarios deben tener acceso a esta funcionalidad. En este caso, solo los usuarios con rol admin o processing podrán ejecutar el plugin.
Además, el segundo parámetro de la función self.add_task_to_user es el nombre del plugin y la función que se va a ejecutar. Esto es simplemente para identificar la tarea en la base de datos y no afecta el funcionamiento del plugin. Con esto, la función bulk queda de la siguiente manera:
@shared_task(ignore_result=False, name='titleModifier.bulk', queue='low') def bulk(body, user): from openai import OpenAI openai_client = OpenAI(api_key=OPENAI_API_KEY)
def modify_title(client, original_title, model, instructions, input): response = client.responses.create( model = model, instructions = instructions, input = input + original_title ) return response.output_text
filters = { 'post_type': body['post_type'] }
if 'parent' in body: if body['parent'] and len(body['resources']) == 0: filters = {'$or': [{'parents.id': body['parent'], 'post_type': body['post_type']}, {'_id': ObjectId(body['parent'])}], **filters}
if 'resources' in body: if body['resources']: if len(body['resources']) > 0: filters = {'_id': {'$in': [ObjectId(resource) for resource in body['resources']]}, **filters}
# obtenemos los recursos resources = list(mongodb.get_all_records('resources', filters, fields={'_id': 1, 'metadata': 1})) if len(resources) == 0: return 'No se encontraron recursos para procesar'
for resource in resources: original_title = resource['metadata']['firstLevel']['title'] new_title = modify_title(openai_client, original_title, body['model'], body['instructions'], body['input']) update = { 'metadata': { 'firstLevel': { 'title': new_title } } } update_data = RecordUpdate(**update) mongodb.update_record('resources', {'_id': resource['_id']}, update_data)
instance = ExtendedPluginClass('titleModifier','', **plugin_info) instance.clear_cache()
return 'ok'Dentro de la función bulk se define el código que se va a ejecutar al procesar los registros. En este caso, se obtiene el título original del recurso y se envía a la API de OpenAI para que lo modifique. Luego, se actualiza el título del recurso en la base de datos.
Como funciones propias de ArchiHUB, se encuentran las funciones mongodb.get_all_records y mongodb.update_record. La primera función obtiene los registros de la base de datos y la segunda actualiza el registro en la base de datos. Además, al final de la función bulk se llama a la función clear_cache del plugin para que se actualicen los cambios en la interfaz de ArchiHUB. Esto es importante ya que si no se llama a esta función, los cambios no se verán reflejados en la interfaz de ArchiHUB a menos de que se regenere la cache desde los ajustes del aplicativo.
Fila de procesamiento
Sección titulada «Fila de procesamiento»El plugin se ejecuta en una fila de procesamiento. Esto significa que cuando se envía una tarea al plugin, esta se agrega a una fila y se procesa en segundo plano. Esto es útil para distribuir las tareas a diferentes workers y evitar problemas de rendimiento si se ejecuta todo en la misma máquina y fila de procesamiento. En este caso, el plugin usa la fila low para procesar las tareas. Para más información de las filas de procesamiento, revisa la documentación de ArchiHUB.
Campos de interacción con el frontend
Sección titulada «Campos de interacción con el frontend»Para las interacciones desde el frontend, se definen los campos desde la variable plugin_info. Esta variable contiene la información del plugin y se utiliza para mostrar la información en la interfaz de ArchiHUB. En este caso, se están usando diferentes tipos de campo:
- instructions: se utiliza para mostrar un texto de instrucciones al usuario. Este campo no es editable y solo se muestra como información.
- select: se utiliza para mostrar un campo de selección al usuario. En este caso, se está usando para seleccionar el modelo de OpenAI que se va a usar para modificar el título.
- text: se utiliza para mostrar un campo de texto al usuario. En este caso, se está usando para mostrar el campo de instrucciones y el campo de comando para GPT.
Nota: en caso de requerir otros tipos de campos, no dudes en abrir un issue en el repositorio donde se encuentra el frontend de ArchiHUB. Con gusto te ayudaremos a implementarlo. Recuerda que ArchiHUB es un proyecto de código abierto y estamos abiertos a recibir contribuciones de la comunidad.
Repositorio del plugin de ejemplo
Sección titulada «Repositorio del plugin de ejemplo»Para facilitar el entendimiento de la guía, hemos creado un repositorio donde podrás encontrar el plugin desarrollado. Para instalarlo, sigue las instrucciones en la documentación oficial de ArchiHUB.