Cómo escribir una herramienta para generar gráficos con lenguaje natural usando ChatGPT.
Published: 2023-03-22 03:19:29


Con el rápido desarrollo de los grandes modelos del lenguaje, han surgido varias oportunidades de automatización a través del uso del lenguaje natural. En este artículo vamos a ir paso a paso por la creación guiada de un sistema de IA para generar gráficos a partir de un conjunto de datos de forma automatizada. Es una herramienta teórica, y está desarrollada para mostrar lo fácil que es usar la API de ChatGPT para crear nuestros propios proyectos.


## Zero Shot o Few Shots, el concepto clave

¿Te imaginas usar un modelo de inteligencia artificial para resolver tareas para las que no fue entrenado específicamente? Con el auge de los modelos del lenguaje se han generado modelos preentrenados que nos permiten aprovechar una técnica llamada Zero Shot Learning y es fácilmente aplicable usando modelos como ChatGPT.

ChatGPT es una herramienta de procesamiento del lenguaje. Su principal aplicación es la de conversar con los usuarios, por eso generalmente se le clasifica dentro de los modelos conversacionales.

Si bien fue creada para mantener conversaciones con los usuarios, ChatGPT al estar basada en modelos de procesamiento del lenguaje natural, puede ayudarnos a desarrollar muchas tareas de procesamiento del lenguaje usando una técnica llamada “Zero Shot”.

Los modelos donde se pueden aplicar estas técnicas son los modelos preentrenados. Estos representan una gran oportunidad para poder acelerar nuestro trabajo respecto al Deep Learning, debido a que han sido previamente entrenados en grandes volúmenes de datos. Usar modelos preentrenados para resolver tareas rutinarias en nuestras aplicaciones de inteligencia artificial nos puede ahorrar mucho tiempo y recursos.

¿Pero qué es Zero Shot? El concepto de “Zero Shot Learning” no es nuevo, lleva varios años dando vueltas por el campo de la inteligencia artificial. El Zero Shot Learning es un paradigma para trabajar con modelos preentrenados. Este paradigma nos indica que los modelos preentrenados pueden desarrollar tareas para las que no fueron entrenados explícitamente.

Las técnicas de Zero Shot representan una oportunidad para el desarrollo de múltiples aplicaciones, esto debido a que permiten usar y adaptar modelos para tareas distintas a las que fueron entrenados.

No tenemos que confundir las técnicas de Zero Shot con las técnicas de Transfer Learning. En el Transfer Learning se reentrena un modelo para aplicarlo a un problema distinto al original. Para el Zero Shot no se necesita entrenamiento adicional, simplemente saber cómo expresar la tarea a resolver.

Un ejemplo Zero Shot Q&A:

Q: Roger tenía 16 pelotas de distintos tipos. La mitad eran pelotas de golf y la mitad de las pelotas de golf eran azules. ¿Cuántas pelotas azules tenía Roger?
A: 

Respuesta:
Roger tenía 4 pelotas azules.

Si la mitad de las 16 pelotas eran de golf, eso significa que tenía 8 pelotas de golf. Y si la mitad de las pelotas de golf eran azules, entonces tenía 4 pelotas de golf azules. Por lo tanto, Roger tenía 4 pelotas azules en total.

Si bien esta técnica es efectiva para desarrollar aplicaciones, podemos mejorarla cuando le damos ejemplos y seguimos un patrón más parecido al aprendizaje por una muestra (one-shot learning).



![One Shot Learning Prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0plt3kkw24uojve87zn9.png)


Dentro de este prompt podemos reconocer 4 secciones importantes:
1. El prompt principal, el que provee instrucciones y una descripción general de la tarea
2. Las categorías a clasificar
3. El texto a clasificar
4. Las instrucciones adicionales.


![One Shot Learning Anotated](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpl2evtgay3wd7r0zfyv.png)


Pero vamos a volver al tema más adelante, por ahora solo mantén en mente que este patrón de pregunta es más efectivo para las respuestas que un patrón basado en **Zero Shot Learning** o **One Shot** para usarlo en tareas relativas al **Natural Language Understanding**.

A pesar de las ventajas que ofrecen el **Zero Shot Learning** y el **One Shot Learning**, como la posibilidad de aplicar modelos preentrenados a una gran variedad de tareas que involucran el procesamiento del lenguaje natural y la reducción del costo computacional y temporal, también hay que reconocer los desafíos y limitaciones asociados a estas dos técnicas, como la falta de consistencia y la dificultad para evaluar los resultados generados por los modelos.

## Pensando en ChatGPT como un compresor de datos

Los compresores de datos son programas que tienen por finalidad reducir el tamaño de los datos. Los modelos de lenguaje son modelos capaces de predecir la siguiente palabra de una secuencia de palabras, pero ¿cómo podemos relacionar estos dos conceptos?

Si tomamos en cuenta el volumen de los datos con los que está entrenado ChatGPT, podemos cuantificarlo de muchas formas, pero no se puede negar que ChatGPT es una representación compacta de esa cantidad masiva de datos.

Una manera de considerar al **prompt**, es como una herramienta para filtrar información que el modelo tiene en sus datos de entrenamiento, y al modelo como una estructura que codifica toda la información que queremos obtener.

Por ejemplo, supongamos que queremos usar a ChatGPT para generar una pregunta para un examen de sociologia podriamos usar el siguiente prompt:

```
Pregunta teorica para un examen de sociologia.

Si consideramos el concepto Materialismo historico propuesto por Karl Marx, podriamos afirmar que:

a. ___________ (Alternativa a maximo 200 caracteres)
b. ___________ (Alternativa b maximo 200 caracteres)
c. ___________ (Alternativa c maximo 200 caracteres)
d. ___________ (Alternativa d maximo 200 caracteres)

Repuesta correcta:
_ (Alternativa para la respuesta correcta)

¿Puedes completar la plantilla?

Respuesta:
Si consideramos el concepto Materialismo histórico propuesto por Karl Marx, ¿podríamos afirmar que:

a. La economía es el motor de la historia, y los conflictos entre clases sociales son la principal fuerza impulsora del cambio social.

b. El desarrollo tecnológico y científico es el principal factor que determina el curso de la historia.

c. La religión es la fuente de todos los conflictos sociales y políticos.

d. El individualismo es la principal causa de la desigualdad social.

La respuesta correcta es:
a. La economía es el motor de la historia, y los conflictos entre clases sociales son la principal fuerza impulsora del cambio social.
```

En este ejemplo podemos observar que al utilizar un **prompt** específico, estamos filtrando la información que el modelo ChatGPT posee respecto al concepto de **materialismo histórico**. Estamos guiando de cierta manera al modelo a generar una pregunta relacionada con esta teoría sociológica en particular. De esta manera, el **prompt** tiene la función de controlar el tipo de información que el modelo utiliza para generar la respuesta deseada. Con esto podemos observar cómo se puede percibir al **prompt** como *una herramienta para filtrar la información de un modelo de procesamiento del lenguaje*, en este caso ChatGPT.


Si lo pensamos de esta manera, el **prompt** es la forma de buscar información dentro de ChatGPT, en cierta manera una forma de filtrar ese volumen masivo de datos comprimidos dentro de sus parámetros. Por lo tanto, para filtrar exactamente la información que queremos tenemos que seguir algunos pasos que he podido notar en mi proceso de experimentación directo con ChatGPT:


1. Ser específico: Siempre tenemos que intentar ser lo más específico posible y eliminar cualquier posible concepto ambiguo en nuestro prompt.

2. Proveer ejemplos: Proveer ejemplos sobre cómo contestar es clave para poder obtener buenas respuestas por parte del modelo. 

3. Proveer un formato claro de respuesta: Proveer plantillas y un formato claro de cómo responder puede ser bastante ventajoso al momento de ocupar ChatGPT para desarrollar aplicaciones, debido a que si podemos hacer que el modelo facilite el proceso, de postprocesado de datos, ahorraremos mucho tiempo de escritura de código.

La pregunta más grande que se puede generar en este momento es: ¿Por qué estos consejos funcionan?.

## Los modelos de lenguaje son aprendices de pocas muestras

En 2020, OpenAI publicó un artículo llamado "Language Models Are **Few Shot Learning**" que puede ayudarnos a comprender cómo mejorar los prompts de **ChatGPT**. En él, se explican algunas pistas sobre cómo entrenaron a GPT-3 utilizando una técnica llamada **"Few Shot Learning"**.

Esta técnica se basa en el aprendizaje automático que permite realizar una tarea específica a partir de pocos ejemplos de entrenamiento y generalizarlos a nuevas aplicaciones. Se inspira en la forma en que los humanos aprendemos, donde no solo adquirimos conocimientos teóricos, sino que también aprendemos a partir de ejemplos concretos.

Por ejemplo, si vemos un animal con cuatro patas, pelo y cola, podemos deducir que es un mamífero, mientras que si vemos un animal con aletas, escamas y agallas, podemos decir que es un animal marino. Esto demuestra que el conocimiento no se basa únicamente en teorías, **sino que también se relaciona con ejemplos concretos que nos ayudan a realizar las tareas que se nos piden**.

Sabiendo los detalles del *proceso de entrenamiento* de **GPT-3**, podemos mejorar nuestras capacidades de prompting. Por ejemplo, en lugar de pedirle a **ChatGPT** que "Describa un león", es recomendable proporcionar varios ejemplos para aclarar el concepto de "descripción", proporcionando ejemplos de descripciones de otros animales, por ejemplo:

```
Ejemplos de descripción de animales:
- El tigre es un animal con 4 patas, pelo y cola. Los tigres se encuentran en hábitats increíblemente diversos, por ejemplo "selvas tropicales" (...)

- El búho es un ave con 2 patas, 2 alas, y plumas. Los búhos habitan típicamente en los bosques (...)

Ahora, describe un león.
```


Estos ejemplos ayudarán a **ChatGPT** a entender el tipo de descripción precisa que estás buscando y pueden lograr que **ChatGPT** te proporcione detalles específicos, use una plantilla, etc.

Pero hay que tener en cuenta que las peticiones deben contener información relevante sobre cómo resolver la tarea que estamos pidiendo. Es importante dividir tu petición en partes pequeñas que aporten los detalles necesarios para responder a la petición de manera adecuada.

Con estos conceptos en mente, podemos mejorar los prompts que hacemos a **ChatGPT** para lograr respuestas más efectivas y útiles en diversas aplicaciones.

Para pedir a **ChatGPT** que resuelva una tarea específica, es importante proporcionarle varios ejemplos sobre cómo resolverla y cómo responder a la petición. Esto se debe a que los *modelos de lenguaje*, como **ChatGPT**, están diseñados para aprender a partir de pocos ejemplos utilizando la técnica de **Few Shot Learning**, que se basa en la idea de que los humanos también aprendemos a partir de ejemplos.

Además, es importante entender el concepto de *"tokens"*. Los *tokens* son las unidades mínimas utilizadas para procesar texto. Cuando se procesa texto para **ChatGPT**, se divide en *tokens* para poder procesarlo de manera efectiva. La cantidad de *tokens* en una entrada determina la calidad de la respuesta generada por el modelo. Sin embargo, no es solo la cantidad de *tokens* lo que importa. También es importante que los *tokens* sean relevantes y proporcionen información adicional sobre la respuesta específica que se busca.

Si deseas conocer la cantidad de *tokens* que tiene tu petición y aprender más sobre cómo se preprocesa el texto de entrada para GPT-3, puedes usar el siguiente enlace, que utiliza una implementación de GPT-3-Encoder: https://platform.openai.com/tokenizer.

## El verdadero potencial oculto en LangChain 🦜

**LangChain** es una herramienta que facilita la creación de aplicaciones basadas en modelos del lenguaje. Algunos ejemplos de los modelos que se pueden utilizar mediante la librería **LangChain** son GPT-3, BERT o ChatGPT.

Los modelos del lenguaje se pueden emplear para realizar diferentes tareas, como se ha demostrado anteriormente, aprovechando la capacidad de generalización de un modelo para realizar diversas tareas. Para explotar el potencial de los diferentes modelos del lenguaje es necesario crear una infraestructura de código que les permita interactuar con otras herramientas y fuentes de datos o con el usuario final.

Aquí es donde entra **LangChain**. Con esta librería se pueden crear diferentes cadenas de ejecución, gestionar los prompts, diseñar agentes, gestionar y almacenar los datos generados por los diferentes modelos, etc.

Conocí Langchain leyendo el código de **Visual ChatGPT** publicado por Microsoft. El paper presentaba un nuevo paradigma para el desarrollo de agentes conversacionales capaces de **enviar y recibir imágenes a través del chat**. Esto me pareció muy innovador y así fue como se me ocurrió el siguiente proyecto.

En concreto **Visual ChatGPT** usaba Langchain para comunicar a GPT-3 con una serie de *modelos fundamentales visuales* especializados en distintos dominios. Por ejemplo:

- Modelos para editar imágenes
- Modelos para generar imágenes
- Modelos pix2pix
- etc.

Todos estos modelos conformaban un *toolkit* y se usaba **ChatGPT** como un intermediario entre el usuario y estas herramientas; es decir, **ChatGPT** sabía operar con este *toolkit*. Lo que más me llamó la atención es que no era necesario reentrenar al modelo para poder aplicar el paradigma y ahí es donde vi la innovación. De pronto se me ocurrió implementar este mismo patrón para varios proyectos, incluido el que voy a mostrar a continuación.

No voy a profundizar en cada una de las capacidades de LangChain, pero si estás interesado en saber más sobre la librería, puedes visitar su documentación: https://langchain.readthedocs.io/en/latest/index.html.

Para este proyecto solo usaré el Prompt Template y el LLMChain, ya que son bastante fáciles de implementar y entender incluso si no tienes conocimientos previos sobre LangChain, pero los explicaré brevemente antes de pasar al código:

- El prompt template es **una forma estandarizada para definir la entrada y la salida esperada de un modelo del lenguaje**, como hemos visto anteriormente, tenemos que pensar en el prompt como una herramienta para filtrar datos; por lo tanto, el PromptTemplate nos permite **adaptar el modelo a una tarea específica o personalizar su comportamiento**.

- El LLMChain **permite definir una llamada al modelo del lenguaje con los parámetros que queramos usar**, se usa para comunicarse con la **API de un modelo y recibir una respuesta en formato string**.

## PlotGPT: Una aplicación creada con ChatGPT.

PlotGPT es una herramienta que facilita la generación de visualizaciones simples de los datos usando a **ChatGPT** como una interfaz. Se basa en **ChatGPT** del lenguaje especializado en conversaciones, el rol que cumple es interpretar las peticiones del usuario y producir el código en Python y los gráficos correspondientes.

La entrada de PlotGPT es una petición en *lenguaje natural* que especifica el tipo y los datos a utilizar en el gráfico a generar, por ejemplo: "Show me a bar plot with the month revenues". El código generado se puede modificar para personalizar le gráfico posteriormente.

Esta implementación no es más que una prueba de concepto que ilustra las posibilidades de ChatGPT cuando se combina con LangChain. No se trata de una solución optima ni definitiva, sino una forma de explorar las capacidades del modelo y sus limitaciones. Este proyecto ésta hecho con propositos de investigación y no se trata de un producto real.

El primer paso es obtener nuestro *api key de OpenAI* y configurarla como variable del sistema.

Para obtener un *API key de openAI*, puedes dirigirte al siguiente [enlace](https://platform.openai.com/), registrarte, y solicitarla.

Despues vamos a instalar las siguientes librerias:
```py
pip install langchain
pip install openai
pip install pandas
pip install matplotlib
```
Una vez hecho esto, podemos empezar. Lo primero que tenemos que hacer para desarrollar la aplicación es crear nuestro sistema de archivos para organizar el código. Mi estructura es la siguiente:
```
carpeta_principal
|
+-- src
    |
    |_src.py
|_ main.py
```
El archivo src.py puede tener el nombre que prefieras. Yo le decidí llamar `templates.py`, debido a que ahí tengo todos los templates de los prompts para ChatGPT.

Lo primero que vamos a revisar es cómo hacer los *prompts* para que ChatGPT haga lo que esperamos. La forma en que yo lo hice fue subdividir las tareas en 3 partes: la primera recibe el *prompt del usuario* y genera código; la segunda extrae el código de Python; y la tercera detecta las dependencias del código generado, esto es con el propósito de saber si hay que instalar librerías adicionales.

Para el primer ejemplo hice una estructura con 3 ejemplos, los cuales son los siguientes:

```py
[    {        
        "question": "Can you select the 'name' and 'age' columns from the database",       
        "answer": "pandas_dataframe.loc[:, ['name', 'age']]"
        },    
        {        
        "question": "Can you calculate the average of the 'age' column from the database",        
        "answer": "pandas_dataframe['age'].mean()"    
        },    
        {        
        "question": "Can you plot the 'age' and 'income' columns from the database",        
        "answer": "pandas_dataframe.plot(x='age', y='income')"    
        }
]
```

Lo que pretendo hacer con estos ejemplos es proveer suficiente información al modelo sobre cómo resolver la tarea:

- El lenguaje de programación, en este caso Python.
- El uso de pandas para filtrar los datos.
- El formato de respuesta.

El prompt completo que incluye todos los ejemplos es el siguiente:
```py
    database_query_prompt = PromptTemplate(
        input_variables=['columns', 'query'],
        template=f"Following the reasoning: \nFor example: {examples[0]['question']}\n{examples[0]['answer']}\n{examples[1]['question']}\n{examples[1]['answer']}\n{examples[2]['question']}\n{examples[2]['answer']}\nWithin the following database we have the following columns"+"{columns}. How can I {query} from the variable pandas_dataframe?. Give only one answer and don't include any library imports. Actual code: \```py import pandas as pd\nimport matplotlib.pyplot as plt\npandas_dataframe('db_csv')\``` continue the code
        """,
    )
```

*PromptTemplate* Es un objeto que se comunica con LangChain para poder llevar a cabo la cadena de ejecución.

El resto del prompt especifica a ChatGPT que siga los ejemplos anteriores, y también se les provee el nombre de las columnas del dataframe utilizado, y también se le provee el input del usuario, esto específicamente en este punto:
```py
{columns}. How can I {query}
```

Los inputs variables son los identificadores de las variables dentro del template. Esto permite que LangChain pueda sustituir los identificadores por los valores correspondientes a la cadena, pero esto lo explicaremos más adelante.

A continuación, defino otros parámetros como la variable `pandas_dataframe`, y también especifico el formato de las respuestas y le indico a ChatGPT que utilice las librerías `matplotlib` y `pandas`. Después le pido que genere el código.

El siguiente prompt que creé fue para filtrar la salida del primer prompt. La finalidad del segundo prompt es extraer únicamente el código del primero. Esto se debe a que la salida de ChatGPT no era muy precisa, pese a todas las indicaciones previas. Por eso, elaboré un segundo prompt con ejemplos que es el siguiente:

```py
code_extraction_prompt = PromptTemplate(
        input_variables=['generated_text'],
        template= """
        This are 3 examples of how extract code from text:
           Begin Example 1
              User Input:
                The answer for the question can you make a program that prints hello world is:
                \```
                print("hello world")
                \```
                However, the code is very basic because it only prints hello world.
              Your Output:
                \```
                    print("hello world")
                \```
            End Example 1
            Begin Example 2
                User Input:
                    The answer for the "fibonacci sequence of 10" is:
                    def fibonacci(n):
                        if n <= 1:
                            return n
                        else:
                            return(fibonacci(n-1) + fibonacci(n-2))
                    print(fibonacci(10))
                    Note that the variable n is the number of the fibonacci sequence. is the number of the fibonacci sequence.
                Your Output:
                    \```
                    def fibonacci(n):
                        if n <= 1:
                            return n
                        else:
                            return(fibonacci(n-1) + fibonacci(n-2))
                    print(fibonacci(10))
                    \```
            End Example 2
            Begin Example 3
                User Input:
                    The code for select the columns 'name' and 'age' from the database is:
                        pandas_dataframe.loc[:, ['name', 'age']]
                    However it seems the columns names that you provide are not corect.
                Your Output:
                    \```
                    pandas_dataframe.loc[:, ['name', 'age']]
                    \```
            End Example 3

            Now that you have seen 3 examples of how to extract code from text, please extract the code from the following text:
            Important:  Only give your answer, dont give any additional text, only the answer.
            
            User Input:
                {generated_text}
            Your Output: 
         """
```

En este caso, integré los ejemplos al prompt completamente. Además, definí claramente dónde empieza y termina cada ejemplo. Por lo general, este segundo método funciona mucho mejor que el primero.

Los 3 ejemplos muestran cómo extraer el código del prompt previo. Este prompt no depende del nombre de las columnas ni de las variables ni nada parecido. Su única función es separar el código del texto generado por ChatGPT. Después de los 3 ejemplos proporcionados se indica la tarea a realizar y se sigue el mismo formato que en los ejemplos.

Decidí hacerlo así porque las IAs como ChatGPT están diseñadas para predecir la siguiente palabra de una secuencia. Así que si les das ejemplos de cómo completar la secuencia y al final les das una plantilla igual a la de los ejemplos es más probable que el modelo siga la secuencia de los ejemplos dados al inicio del prompt.

Y para acabar le damos un prompt para obtener más información del código generado por ChatGPT con el siguiente y último prompt:

```py    
code_analysis_prompt = PromptTemplate(
        input_variables=['generated_code'],
        template="""
        There is a lot of information that can be extracted from code. I will give you 3 examples of how to extract information from code.
        Begin Example 1
            User Input:
                pandas_dataframe['Sex'].value_counts().plot(kind='bar')
                plt.xticks([0, 1], ['Man', 'Woman'])
                plt.show()
            Your Thought Process Will be:
                Dependencies: Pandas, Matplotlib
                Requires Plotting: True
                Requires Result Printing: False
            Your Output:
                ["Pandas, Matplotlib", True, False]
        End Example 1

        Begin Example 2
            User Input:
                def fibonacci(n):
                    if n <= 1:
                        return n
                    else:
                        return(fibonacci(n-1) + fibonacci(n-2))
                print(fibonacci(10))
            Your Thought Process Will be:
                Dependencies: None
                Requires Plotting: False
                Requires Result Printing: True
            Your Output:
                ["None", False, True]
        End Example 2
        
        Begin Example 3
            User Input:
                pandas_dataframe['age'].mean()
            Your Thought Process Will be:
                Dependencies: Pandas
                Requires Plotting: False
                Requires Evaluation: True
            Your Output:
                ["Pandas", False, True]
        Can you give me Your Output for the following code supressing your thought process, is important that you only give me the output, not the input or any other text, and dont repeat "Your Output:" Only give me the dependecies, requires ploting, and requires result printing nothing more.
            {generated_code}
        Your Output:
        """
    )
```

Aquí adopto un tercer patrón para optimizar los prompts. Como este proyecto es solo una muestra, los 3 prompts tienen patrones distintos. En este caso quiero que identifique las dependencias, si necesita generar un gráfico o si solo necesita evaluar el código y mostrar un resultado. Estas 3 categorías son fundamentales para saber cómo ejecutar el código, crear la plantilla o guardar una imagen del gráfico si hace falta.

Cuando llegué a este último prompt pensé en formas más elaboradas de comunicarme con ChatGPT, pero vi que lo más sencillo era darle ejemplos de cómo obtener los valores finales y que me devolviera directamente una lista de Python fácil de *"parsear"* con Python. Entonces le digo "Your Thought Process Will be"... Así ChatGPT sabe cómo conseguir los valores que va a poner en la lista.

Ya enseñé los prompts, pero creo que antes de continuar con mi implementación hay que detenerse y preguntarse: ¿Por qué esto funciona realmente?

### Stop para profundizar
¿Recuerdas que al inicio hablamos sobre dejar la explicación del Few Shot Learning para el final?

Sin embargo, los casos en que usamos los paradigmas One Shot y Zero Shot no entregaban buenos resultados. El nivel de especificidad de los resultados no era suficiente para desarrollar una aplicación. Esto se debe principalmente a que en el paradigma Zero Shot el modelo intenta adivinar lo que nosotros le estamos pidiendo y responder de una manera que satisface las condiciones que les entregamos.

Por eso elegí el estilo Few Shot. El modelo tiene bastante más información sobre cómo realizar la tarea e incluso puede sortear las ambigüedades que irán apareciendo en la respuesta. En este caso el modelo no está encontrando la mejor forma de responder a una pregunta sino que está replicando el formato que le proveímos y adaptándolo a una respuesta generada por él mismo.

Según mis observaciones para el desarrollo de tareas relacionadas con el NLU (Natural Language Understanding) siempre necesitaremos proveer ejemplos a los modelos de procesamiento del lenguaje actual.

También es recomendable para evitar ambigüedades como en el último ejemplo darle ejemplos sobre cómo se llega a la respuesta final. Esto una vez más puede ayudar a quitar las ambigüedades que puedan presentarse en la respuesta del modelo. Una vez dicho esto vamos a continuar con la implementación.


### Explicando el resto de la implementación en Python

A continuación definimos las cadenas. Las cadenas son secuencias de pasos que permiten transferir la información desde nuestro programa a los modelos de lenguaje. Para ello debemos añadir el siguiente código en Python:
```py
    chain_code_generation = LLMChain(llm=llm, prompt=database_query_prompt)
    chain_code_extraction = LLMChain(llm=llm, prompt=code_extraction_prompt)
    chain_code_analysis = LLMChain(llm=llm, prompt=code_analysis_prompt)
```

A continuación definí los parámetros de entrada del primer modelo en un diccionario y ejecuté la cadena completa. Luego realicé una limpieza básica a los resultados:

```py
    params ={
        "columns": pandas_dataframe.columns,
        "query": query
    }
    output = chain_code_generation.run(**params)

    code = chain_code_extraction.run(generated_text=output)

    # Actual code is between the "\`\`\`py" and "\`\`\`"
    code = code.replace("\\`\`\`py", "").replace("\`\`\`", "")
    analysis = chain_code_analysis.run(generated_code=code)

    return code, analysis
```

Luego cree un par de funciones auxiliares para generar el archivo final y ejecutarlo:

```py
def code_inyection(generated_code_path, db_path, model_code, model_analysis):
    print("Inyection")
    generated_code = []
    # Agregamos pandas
    if "Pandas" in model_analysis:
        generated_code.append("import pandas as pd")
    # Agregamos matplotlib
    if "Matplotlib" in model_analysis:
        generated_code.append("import matplotlib.pyplot as plt")
    
    # Agregamos los preparativos teniendo en cuenta el nombre del dataframe es los ejemplo 
    # Proveidos en los prompts
    generated_code += f"pandas_dataframe = pd.read_csv('{db_path}')", model_code.replace("plt.show()", "").
    
    # Corregimos cualquier problema de indentaión
    replace("\t", "").replace(" ", "")
    
    # Model Analysis input: ["Pandas, Matplotlib", True, False]
    # Parseamos el analisis de dependencias
    model_analysis = model_analysis.replace("[", "").replace("]", "").replace("'", "").split(", ")
    # Guardamos el codigo y la imagen
    plot_image_path = None
    if model_analysis[2] == "True":
        plot_image_path = "plot.png"
        generated_code.append(f"plt.savefig('{plot_image_path}')")
    generated_code = "\n".join(generated_code)
    with open(generated_code_path, "w+") as f:
        f.write(generated_code)

    return generated_code_path, plot_image_path, generated_code

# Usamos os.system para ejecutar el codigo generado
def execute_code(file_path):
    print("Excecuting")
    os.system(f"python {file_path}")

```

Para finalizar la implementación, cree una API Simple en Flask:

```py
from src.templates import fake_db_lookup, code_inyection, execute_code
from flask import Flask, request, jsonify
from langchain.llms import OpenAI
import os
from pathlib import Path
app = Flask(__name__)

@app.route("/")
def index():
    # Función de prueba
    return jsonify({"hello": "World"})

llm = OpenAI(openai_api_key=os.environ["OPENAI"], temperature=.1)

# Parse the text query and return the code and analysis
@app.route("/generate_code", methods=["GET"])
def generate_code():
    # Recibimos los parametros y extraemos el Query
    query: str = request.args.get("query")
    
    # Si falta el Query enviamos un error
    if query is None:
        return jsonify({"error": "No query provided"})
    
    # Generamos el codigo 
    code, analysis = db_lookup(query=query, llm=llm)
    file_path, plot_image_path, generated_code = code_inyection("/home/yo/code.py", "db.csv", code, analysis)
    execute_code(file_path)
    p = Path(plot_image_path).absolute() if plot_image_path else "Not Provided"
    
    # Generamos una respuesta en JSON
    response = {
        "code": generated_code,
        "plot": str(p)
    }
    
    
    # Retornamos la respuesta en formato JSON hacia el frontend
    return jsonify(response)

if __name__ == "__main__":
    app.run(debug=True)
```

Y con eso tenemos cubierta la porción mas significativa del backend de mi implementación.

No entraré en detalles con el frontend, lo unico que puedo decir es que use electron ya que la aplicación la pense para el uso local, pero igualmente el codigo del frontend y el backend estan disponibles en el siguiente enlace:

https://github.com/harpiechoise/PlotGPT

## Resultados

El dataset utilizado para hacer estas pruebas, es el dataset Titanic, se puede encontrar fácilmente en Kaggle.

Prompt Original
Can you select 'Sex' column and make a plot with a pie chart and replace the axis labels with 'men' and 'woman' respectively

Resultado:

![Imagen resultado del prompt #1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4q57g3ftpnn3xk7979h2.png)

Prompt Original
Can you select 'Sex' column and make a plot them with a bar chart then rotate the X axis labels 45° and make green and red bars respectly. 

Resultado:

![Imagen resultado del prompt #2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcjiclkpni1z4ntwv8hh.png)

Prompt Original:
Can you make an histogram for 'Age' variable with 10 bins with the title "Age distribution on titanic dataset", with red colored bins?

Resultado:

![Imagen resultado del prompt #3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3qvj1sgkngvd62mfljxk.png)

## Conclusión

En este artículo hemos visto cómo ChatGPT representa una gran oportunidad para agilizar el desarrollo de aplicaciones que antes eran impensables gracias a su gran capacidad de generar textos coherentes y creativos a partir de una entrada entregada por el usuario. Hemos facilitado un punto de entrada para combinar expandir las capacidades de ChatGPT, este mismo patrón se puede aplicar con el fin de generar audio, imágenes, textos, etc. Sin duda siento que en el futuro saldrán otros avances para expandir las fronteras de lo que podríamos lograr gracias a la inteligencia artificial. 

Sin embargo, también hemos conocido que existen algunos riesgos y desafíos asociados a estos patrones de diseño, la ética y la seguridad de los contenidos es nuestra responsabilidad. Por ello, es que gracias a los patrones presentados tenemos la oportunidad de agregar una capa de seguridad a las respuestas del modelo, solo con el uso de prompts. 

En mi opinión, tecnologías como ChatGPT y los modelos similares aportan un avance muy valioso y si sabemos ver la oportunidad, podemos usarlo para facilitar nuestro trabajo y enriquecer nuestra experiencia de usuario. No obstante, tenemos que ser conscientes de sus limitaciones y potenciales peligros.

Espero que este artículo te haya parecido interesante e informativo. Si tienes cualquier duda o comentario sobre el tema, puedes dejarlo en cualquiera de las publicaciones donde haya compartido el link a este artículo. Gracias por leer hasta el final y nos vemos en el próximo artículo.

## Bibliografia

Brown, T. B., Mann, B., Ryder, N., Subbiah, M., Kaplan, J., Dhariwal, P., Neelakantan, A., Shyam, P., Sastry, G., Askell, A., Agarwal, S., Herbert-Voss, A., Krueger, G., Henighan, T., Child, R., Ramesh, A., Ziegler, D. M., Wu, J., Winter, C., … Amodei, D. (2020). Language Models are Few-Shot Learners (arXiv:2005.14165). arXiv. https://doi.org/10.48550/arXiv.2005.14165
Fedewa, J. (s. f.). What Is ChatGPT, and Why Is It Important? Recuperado 20 de marzo de 2023, de https://www.howtogeek.com/871071/what-is-chatgpt/
Murzone, F. (2020, octubre 5). Procesamiento de texto para NLP 1: Tokenización. EscuelaDeInteligenciaArtificial. https://medium.com/escueladeinteligenciaartificial/procesamiento-de-texto-para-nlp-1-tokenizaci%C3%B3n-4d533f3f6c9b
Raja, A. (s. f.). (12) Zero-Shot, One-Shot, Few-Shot Learnings: How the different types of N-Short learning disciplines help Data scientists?! | LinkedIn. Recuperado 20 de marzo de 2023, de https://www.linkedin.com/pulse/zero-shot-one-shot-few-shot-learnings-how-different-types-raja-csm/
S, A. (S. F.). Welcome to LangChain—🦜🔗 LangChain 0.0.118. https://langchain.readthedocs.io/en/latest/index.html
Shanahan, M. (2023). Talking About Large Language Models (arXiv:2212.03551). arXiv. http://arxiv.org/abs/2212.03551
Soto, J. A. (2019, diciembre 11). Winrar vs 7-Zip vs Winzip - ¿Cual es el mejor descompresor para Windows? - Guía. GEEKNETIC. https://www.geeknetic.es/Noticia/17666/Winrar-vs-7-Zip-vs-Winzip-Cual-es-el-mejor-descompresor-para-Windows.html
Torres, M. E. (2020, abril 22). Modelos de lenguaje en el NLP. Medium. https://monica-echeverrt.medium.com/modelos-de-lenguaje-en-el-nlp-8922dc34753b
Wu, C., Yin, S., Qi, W., Wang, X., Tang, Z., & Duan, N. (2023). Visual ChatGPT: Talking, Drawing and Editing with Visual Foundation Models (arXiv:2303.04671). arXiv. https://doi.org/10.48550/arXiv.2303.04671