AI se encuentra con PowerPoint
AI y PowerPoint se encuentran
Automatizando presentaciones de investigación de empresas con Streamlit, LangChain y Yahoo Finance
Este artículo fue publicado originalmente en el blog de Streamlit el 2 de agosto de 2023.
Introducción
Este artículo te guiará a través de los aspectos internos de la aplicación Instant Insight, un proyecto de código abierto que obtuvo el tercer lugar en el Streamlit Hackathon para Snowflake Summit en mayo de 2023. La aplicación web está diseñada para generar presentaciones de PowerPoint con investigaciones de empresas y diapositivas de propuesta de valor utilizando datos de Yahoo Finance y ChatGPT.
Para establecer un contexto, imaginemos que trabajas en ventas para una empresa B2B de software como servicio con cientos de prospectos y que ofrece los siguientes productos: software de contabilidad y planificación, CRM, chatbot y almacenamiento de datos en la nube. Tu tarea es realizar investigaciones de prospectos, incluyendo análisis financieros y DAFO, explorar el panorama competitivo, crear propuestas de valor y compartir una presentación con tu equipo. Los datos de los prospectos se almacenan en una base de datos Snowflake, que alimenta a tu sistema CRM. Puedes utilizar la aplicación Instant Insight para filtrar rápidamente los prospectos según diversos parámetros. A continuación, selecciona el prospecto que deseas incluir en la presentación y haz clic en el botón para generar la presentación. En un minuto, la presentación de PowerPoint con toda la investigación estará lista para descargar.
La arquitectura de alto nivel de la aplicación se ve así:

Tabla de Contenidos
- Conecta tu aplicación Streamlit a Snowflake
- Crea una interfaz de usuario con filtros dinámicos y una tabla interactiva
- Obtén datos de empresas de Yahoo Finance
- Crea gráficos utilizando Plotly
- Utiliza la API de Clearbit para obtener logotipos de empresas
- Utiliza LangChain y GPT 3.5 LLM para escribir análisis DAFO y propuesta de valor
- Extrae datos estructurados de la respuesta de GPT
- Genera diapositivas utilizando python-pptx
Conecta tu aplicación Streamlit a Snowflake
Primero, obtén algunos datos. Para hacer esto, utiliza el conector Snowflake:
- ¿Qué modelos de Aprendizaje Profundo utilizar con imágenes de reson...
- Análisis de series temporales Modelos ARIMA en Python
- 15+ Herramientas de IA para Desarrolladores (Agosto 2023)
import snowflake.connector# obtén las credenciales de Snowflake desde los secretos de StreamlitSNOWFLAKE_ACCOUNT = st.secrets["snowflake_credentials"]["SNOWFLAKE_ACCOUNT"]SNOWFLAKE_USER = st.secrets["snowflake_credentials"]["SNOWFLAKE_USER"]SNOWFLAKE_PASSWORD = st.secrets["snowflake_credentials"]["SNOWFLAKE_PASSWORD"]SNOWFLAKE_DATABASE = st.secrets["snowflake_credentials"]["SNOWFLAKE_DATABASE"]SNOWFLAKE_SCHEMA = st.secrets["snowflake_credentials"]["SNOWFLAKE_SCHEMA"]@st.cache_resourcedef get_database_session(): """Devuelve un objeto de sesión de base de datos.""" return snowflake.connector.connect( account=SNOWFLAKE_ACCOUNT, user=SNOWFLAKE_USER, password=SNOWFLAKE_PASSWORD, database=SNOWFLAKE_DATABASE, schema=SNOWFLAKE_SCHEMA, )@st.cache_datadef get_data(): """Devuelve un DataFrame de pandas con datos de Snowflake.""" query = 'SELECT * FROM us_prospects;' cur = conn.cursor() cur.execute(query) # Obtén el resultado como un DataFrame de pandas column_names = [col[0] for col in cur.description] data = cur.fetchall() df = pd.DataFrame(data, columns=column_names) # Cierra la conexión a Snowflake cur.close() conn.close() return df# obtén los datos de Snowflakeconn = get_database_session()df = get_data(conn)
Los datos sensibles como tu cuenta de Snowflake, nombre de usuario, contraseña, nombre de la base de datos y esquema se almacenan en secretos y se obtienen llamando a st.secrets (lee más aquí).
A continuación, define dos funciones:
get_database_session() inicializa un objeto de conexiónget_data() ejecuta una consulta SQL y devuelve un DataFrame de pandasUtiliza una consulta SELECT * sencilla para recuperar todos los datos de la tabla us_prospects.
Crear una interfaz de usuario con filtros dinámicos y una tabla interactiva
Ahora usemos un poco de magia de Streamlit para desarrollar una interfaz frontal para la aplicación. Cree un panel lateral que contenga cuatro filtros dinámicos de selección múltiple y agregue una casilla de verificación que permita a los usuarios seleccionar todos los valores.
Los filtros en su aplicación funcionan de forma secuencial. Se espera que los usuarios los apliquen individualmente, de arriba a abajo. Una vez que se aplica el primer filtro, el segundo filtro está disponible y contiene solo etiquetas relevantes. Después de aplicar cada filtro, el DataFrame subyacente se filtra previamente y la variable “num_of_pros” se actualiza para reflejar el número de prospectos seleccionados.
Vea los filtros en acción:

Aquí está el código para crear los dos primeros filtros:
# crear filtros en la barra lateralsidebar.write('**Usa filtros para seleccionar prospectos** 👇')sector_checkbox = st.sidebar.checkbox('Todos los sectores', help='Marque esta casilla para seleccionar todos los sectores')unique_sector = sorted(df['SECTOR'].unique())# si se marca la casilla de seleccionar todos los sectores, seleccionar todos los sectoresif sector_checkbox: selected_sector = st.sidebar.multiselect('Seleccionar Sector', unique_sector, unique_sector)else: selected_sector = st.sidebar.multiselect('Seleccionar Sector', unique_sector)# si un usuario selecciona un sector, permitir marcar la casilla de seleccionar todas las industriasif len(selected_sector) > 0: industry_checkbox = st.sidebar.checkbox('Todas las Industrias', help='Marque esta casilla para seleccionar todas las industrias') # filtrar datos df = df[(df['SECTOR'].isin(selected_sector))] # mostrar el número de prospectos seleccionados num_of_pros = str(df.shape[0])else: industry_checkbox = st.sidebar.checkbox('Todas las Industrias', help='Marque esta casilla para seleccionar todas las industrias', disabled=True) # mostrar el número de prospectos seleccionados num_of_pros = str(df.shape[0])# si se marca la casilla de seleccionar todas las industrias, seleccionar todas las industriasunique_industry = sorted(df['INDUSTRY'].loc[df['SECTOR'].isin(selected_sector)].unique())if industry_checkbox: selected_industry = st.sidebar.multiselect('Seleccionar Industria', unique_industry, unique_industry)else: selected_industry = st.sidebar.multiselect('Seleccionar Industria', unique_industry)# si un usuario selecciona una industria, permitir marcar la casilla de seleccionar todos los estados del prospectoif len(selected_industry) > 0: status_checkbox = st.sidebar.checkbox('Todos los Estados del Prospecto', help='Marque esta casilla para seleccionar todos los estados del prospecto') # filtrar datos df = df[(df['SECTOR'].isin(selected_sector)) & (df['INDUSTRY'].isin(selected_industry))] # mostrar el número de prospectos seleccionados num_of_pros = str(df.shape[0])else: status_checkbox = st.sidebar.checkbox('Todos los Estados del Prospecto', help='Marque esta casilla para seleccionar todos los estados del prospecto', disabled=True)
A continuación, use AgGrid para crear una tabla interactiva que muestre sus datos, permitiendo a los usuarios seleccionar prospectos de generación de diapositivas (lea más aquí).
Coloque una casilla de verificación en cada fila de la tabla, permitiendo a los usuarios seleccionar solo una fila. Además, establezca el ancho de columna personalizado y la altura de la tabla.
Así es como se verá:

Y aquí está el código para crear esta tabla:
from st_aggrid import AgGridfrom st_aggrid.grid_options_builder import GridOptionsBuilderfrom st_aggrid import GridUpdateMode, DataReturnModeimport pandas as pd# creando una tabla dinámica AgGrid y configurando las opcionesgb = GridOptionsBuilder.from_dataframe(df)gb.configure_selection(selection_mode="single", use_checkbox=True)gb.configure_column(field='Nombre de la Compañía', width=270)gb.configure_column(field='Sector', width=260)gb.configure_column(field='Industria', width=350)gb.configure_column(field='Estado del Prospecto', width=270)gb.configure_column(field='Producto', width=240)gridOptions = gb.build()response = AgGrid( df, gridOptions=gridOptions, height=600, update_mode=GridUpdateMode.SELECTION_CHANGED, data_return_mode=DataReturnMode.FILTERED_AND_SORTED, fit_columns_on_grid_load=False, theme='alpine', allow_unsafe_jscode=True)# obtener las filas seleccionadasresponse_df = pd.DataFrame(response["selected_rows"])
Obtener datos de la empresa desde Yahoo Finance
Supongamos que el usuario ha seleccionado una empresa para investigar y necesitas recopilar algunos datos sobre ella. Tu principal fuente de datos es Yahoo Finance, al cual accederás con la biblioteca yahooquery, una interfaz de Python para los puntos finales no oficiales de la API de Yahoo Finance. Permite a los usuarios recuperar casi todos los datos visibles a través de la interfaz de Yahoo Finance.
Aquí está la diapositiva general con los datos de Yahoo Finance:

Utiliza la clase Ticker de yahooquery para obtener datos cuantitativos y cualitativos sobre una empresa seleccionada. Simplemente pasa el símbolo del ticker de la empresa como argumento, llama a la propiedad requerida y recupera los datos del diccionario devuelto.
Aquí está el código que recupera los datos para la diapositiva general de la empresa:
from yahooquery import Ticker
selected_ticker = 'ABC'
ticker = Ticker(selected_ticker)
# Obtener información de la empresa
name = ticker.price[selected_ticker]['shortName']
sector = ticker.summary_profile[selected_ticker]['sector']
industry = ticker.summary_profile[selected_ticker]['industry']
employees = ticker.summary_profile[selected_ticker]['fullTimeEmployees']
country = ticker.summary_profile[selected_ticker]['country']
city = ticker.summary_profile[selected_ticker]['city']
website = ticker.summary_profile[selected_ticker]['website']
summary = ticker.summary_profile[selected_ticker]['longBusinessSummary']
La aplicación utiliza los datos de Yahoo Finance para crear gráficos que ilustran el rendimiento financiero a lo largo del tiempo. Una diapositiva muestra métricas financieras básicas como el precio de las acciones, la deuda total, los ingresos totales y el EBITDA a lo largo del tiempo.
Hablaré sobre la generación de gráficos más adelante. Por ahora, centrémonos en obtener datos financieros de Yahoo Finance. Las funciones get_stock() y get_financials() devuelven dataframes con métricas financieras relevantes. Los datos del precio de las acciones se almacenan por separado de otras métricas financieras, por eso se llaman dos propiedades:
ticker.history() para recuperar datos de precios históricos para el símbolo o símbolos dados (leer la documentación aquí)ticker.all_financial_data() para recuperar todos los datos financieros, incluyendo el estado de resultados, el balance general, el flujo de efectivo y las medidas de valoración (leer la documentación aquí)
Aquí está el código utilizado para generar cuatro dataframes con el precio histórico de las acciones, los ingresos, la deuda total y el EBITDA:
from yahooquery import Ticker
import pandas as pd
def get_stock(ticker, period, interval):
"""Función para obtener datos de acciones de Yahoo Finance. Toma como argumentos el símbolo, el período y el intervalo y devuelve un DataFrame"""
hist_df = ticker.history(period=period, interval=interval)
hist_df = hist_df.reset_index()
# Capitalizar los nombres de las columnas
hist_df.columns = [x.capitalize() for x in hist_df.columns]
return hist_df
def get_financials(df, col_name, metric_name):
"""Función para obtener métricas financieras de un DataFrame. Toma como argumentos el DataFrame, el nombre de la columna y el nombre de la métrica y devuelve un DataFrame"""
metric = df.loc[:, ['asOfDate', col_name]]
metric_df = pd.DataFrame(metric).reset_index()
metric_df.columns = ['Símbolo', 'Año', metric_name]
return metric_df
selected_ticker = 'ABC'
ticker = Ticker(selected_ticker)
# Obtener todos los datos financieros
fin_df = ticker.all_financial_data()
# Crear dataframes para cada métrica
stock_df = get_stock(ticker=ticker, period='5y', interval='1mo')
rev_df = get_financials(df=fin_df, col_name='TotalRevenue', metric_name='Ingresos Totales')
debt_df = get_financials(df=fin_df, col_name='TotalDebt', metric_name='Deuda Total')
ebitda_df = get_financials(df=fin_df, col_name='NormalizedEBITDA', metric_name='EBITDA')
Los datos de Yahoo Finance también se utilizan en otra diapositiva para el análisis de competidores, donde se compara el rendimiento de una empresa con sus pares. Para realizarlo, utiliza dos métricas: los ingresos totales y el % de SG&A sobre los ingresos. Estas métricas están disponibles en el estado de resultados, por lo que utiliza la propiedad ticker.income_statement(), que devuelve un DataFrame (leer más aquí).
La función extract_comp_financials() recupera los ingresos totales y los gastos de venta, generales y administrativos (SG&A) del DataFrame del estado de resultados, y solo conserva los datos del año 2022. Como la métrica de SG&A como porcentaje de los ingresos no está disponible directamente, se calcula manualmente dividiendo SG&A entre los ingresos y multiplicando por 100.
La función opera en un diccionario anidado con nombres de empresas como claves y un diccionario con símbolos como valores, luego agrega nuevos valores al diccionario existente:
from yahooquery import Tickerimport pandas as pddef extract_comp_financials(tkr, comp_name, comp_dict): """Función para extraer métricas financieras de competidores. Toma un símbolo, nombre de la empresa y un diccionario anidado con competidores como argumentos y agrega métricas financieras al diccionario""" ticker = Ticker(tkr) income_df = ticker.income_statement(frequency='a', trailing=False) subset = income_df.loc[:, ['asOfDate', 'TotalRevenue', 'SellingGeneralAndAdministration']].reset_index() # mantener solo los datos de 2022 subset = subset[subset['asOfDate'].dt.year == 2022].sort_values(by='asOfDate', ascending=False).head(1) # obtener valores total_revenue = subset['TotalRevenue'].values[0] sg_and_a = subset['SellingGeneralAndAdministration'].values[0] # calcular sg&a como porcentaje de los ingresos totales sg_and_a_pct = round(sg_and_a / total_revenue * 100, 2) # agregar valores al diccionario comp_dict[comp_name]['Ingresos Totales'] = total_revenue comp_dict[comp_name]['SG&A % De Ingresos'] = sg_and_a_pct# ejemplo de diccionariopeers_dict_nested = {'Empresa 1': {'Símbolo': 'ABC'}, 'Empresa 2': {'Símbolo': 'XYZ'}}# extraer datos financieros para cada competidorfor key, value in peers_dict_nested.items(): try: extract_comp_financials(tkr=value['Símbolo'], comp_name=key, dict=peers_dict_nested) # si no se encuentra el símbolo en Yahoo Finance, eliminarlo del diccionario de competidores y continuar except: del peers_dict_nested[key] continue
Después de ejecutar el código anterior, obtenga un diccionario anidado que se parezca a la siguiente estructura:
# ejemplo de diccionario de salida{'Empresa 1': {'Símbolo': 'ABC', 'Ingresos Totales': '1234', 'SG&A % De Ingresos': '10'}, 'Empresa 2': {'Símbolo': 'XYZ', 'Ingresos Totales': '5678', 'SG&A % De Ingresos': '20'}}
A continuación, convierta el diccionario anidado en un DataFrame para pasarlo a una función de trazado:
# crear un dataframe con datos financieros de los competidorespeers_df = pd.DataFrame.from_dict(peers_dict_nested, orient='index')peers_df = peers_df.reset_index().rename(columns={'index': 'Nombre de la Empresa'})
El DataFrame resultante debería tener un aspecto similar a esto:
Nombre de la Empresa Símbolo Ingresos Totales SG&A % De Ingresos0 Empresa 1 ABC 1234 101 Empresa 2 XYZ 5678 20
Crear gráficos usando Plotly
¡Has filtrado los datos financieros, ahora es hora de representarlos gráficamente! Utiliza Plotly Express para crear gráficos simples pero visualmente atractivos (lee más aquí).
En la sección anterior, creaste un DataFrame y una variable para el nombre de la empresa. Utilízalos en la función plot_graph() para tomar el dataframe, los nombres de las columnas para los ejes x e y, y el título del gráfico como argumentos:
import plotly.express as pxdef plot_graph(df, x, y, title, name): """función para trazar un gráfico de línea. Toma DataFrame, ejes x e y, título y nombre como argumentos y devuelve una figura de Plotly""" fig = px.line(df, x=x, y=y, template='simple_white', title='<b>{} {}</b>'.format(name, title)) fig.update_traces(line_color='#A27D4F') fig.update_layout(paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)') return figstock_fig = plot_graph(df=stock_df, x='Fecha', y='Apertura', title='Precio de las Acciones en USD', name=name)rev_fig = plot_graph(df=rev_df, x='Año', y='Ingresos Totales', title='Ingresos Totales en USD', name=name)debt_fig = plot_graph(df=debt_df, x='Año', y='Deuda Total', title='Deuda Total en USD', name=name)ebitda_fig = plot_graph(df=ebitda_df, x='Año', y='EBITDA', title='EBITDA en USD', name=name)
Los gráficos resultantes deberían verse algo así:

La aplicación también genera una diapositiva que contiene un análisis de competidores para una empresa dada. Para hacerlo, utiliza la función peers_plot() junto con peers_df. Esta función genera un gráfico de barras horizontales que compara los ingresos totales y el % de ingresos de SG&A entre los competidores.
Aquí está el código:
import plotly.express as px
import pandas as pd
def peers_plot(df, name, metric):
"""Función para graficar un gráfico de barras con competidores. Toma DataFrame, nombre, métrica y ticker como argumentos y devuelve un objeto Plotly"""
# eliminar filas con métricas faltantes
df.dropna(subset=[metric], inplace=True)
df_sorted = df.sort_values(metric, ascending=False)
# iterar sobre las etiquetas y agregar los colores al diccionario de mapeo de colores, resaltar la empresa seleccionada
color_map = {}
for label in df_sorted['Company Name']:
if label == name:
color_map[label] = '#A27D4F'
else:
color_map[label] = '#D9D9D9'
fig = px.bar(df_sorted, y='Company Name', x=metric,
template='simple_white', color='Company Name',
color_discrete_map=color_map,
orientation='h',
title='<b>{} {} vs Competidores FY22</b>'.format(name, metric))
fig.update_layout(paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)', showlegend=False, yaxis_title='')
return fig
# graficar gráficos de competidores
rev_peers_fig = peers_plot(df=peers_df, name=name, metric='Total Revenue')
sg_and_a_peers_fig = peers_plot(df=peers_df, name=name, metric='SG&A % Of Revenue')
El uso de colores personalizados hace que tu empresa se destaque.
Los gráficos de barras deberían verse algo así:

Usar la API de Clearbit para obtener logotipos de empresas
Como viste en la diapositiva de información general de la empresa, había un logotipo de la empresa investigada. Las URL de los logotipos no están disponibles en Yahoo Finance, así que utiliza Clearbit en su lugar. Simplemente conecta el sitio web de la empresa a “https://logo.clearbit.com/” con unas pocas líneas de código:
from yahooquery import Ticker
selected_ticker = 'ABC'
ticker = Ticker(selected_ticker)
# obtener el sitio web de la empresa seleccionada
website = ticker.summary_profile[selected_ticker]['website']
# obtener la URL del logotipo de la empresa seleccionada
logo_url = '<https://logo.clearbit.com/>' + website
Ahora que tienes la URL del logotipo, verifica si funciona. Si lo hace, ajusta su tamaño y colócalo en una diapositiva. Para hacer esto, utiliza la función personalizada resize_image(), que coloca una imagen de logotipo dentro de un contenedor y ajusta su tamaño manteniendo su relación de aspecto. Esto asegura que todos los logotipos se vean iguales a pesar de las diferencias iniciales de tamaño.
Luego guarda el objeto de imagen localmente como “logo.png” y recupéralo para colocarlo en una diapositiva como una imagen. También puedes colocar figuras de Plotly en las diapositivas de manera similar. Utiliza la biblioteca python-pptx para manipular las diapositivas y formas de PowerPoint de forma programática (más información aquí).
Aquí está el proceso:

El siguiente código utiliza la variable logo_url (definida en el fragmento de código anterior):
from PIL import Image
import requests
from pptx import Presentation
from pptx.util import Inches
import os
def resize_image(url):
"""Función para redimensionar los logotipos manteniendo la relación de aspecto. Acepta una URL como argumento y devuelve un objeto de imagen"""
# abrir imagen desde la URL
image = Image.open(requests.get(url, stream=True).raw)
# si un logotipo es demasiado alto o ancho, entonces haz que el contenedor de fondo sea el doble de grande
if image.height > 140:
container_width = 220 * 2
container_height = 140 * 2
elif image.width > 220:
container_width = 220 * 2
container_height = 140 * 2
else:
container_width = 220
container_height = 140
# crear una nueva imagen con la misma relación de aspecto que la imagen original
new_image = Image.new('RGBA', (container_width, container_height))
# calcular la posición para pegar la imagen de manera que esté centrada
x = (container_width - image.width) // 2
y = (container_height - image.height) // 2
# pegar la imagen en la nueva imagen
new_image.paste(image, (x, y))
return new_image
# crear objeto de presentación
prs = Presentation('template.pptx')
# seleccionar la segunda diapositiva
slide = prs.slides[1]
# verificar si una URL de logotipo devuelve el código 200 (enlace de trabajo)
if requests.get(logo_url).status_code == 200:
# crear objeto de imagen de logotipo
logo = resize_image(logo_url)
logo.save('logo.png')
logo_im = 'logo.png'
# agregar el logotipo a la diapositiva
slide.shapes.add_picture(logo_im, left=Inches(1.2), top=Inches(0.5), width=Inches(2))
os.remove('logo.png')
Ejecutar el código anterior debería colocar un logotipo en la diapositiva:

Usar LangChain y GPT 3.5 LLM para escribir un análisis FODA y una propuesta de valor.
¡Es hora de utilizar la inteligencia artificial para la investigación de tu empresa!
Utilizarás LangChain, un marco de trabajo popular diseñado para simplificar la creación de aplicaciones utilizando ChatOpenAI y modelos LLM de Mensaje Humano/Sistema (más información aquí).
La función generate_gpt_response() toma dos argumentos:
- gpt_input, una indicación que pasarás al modelo
- max_tokens, que limita el número de tokens en la respuesta del modelo
Utilizarás el modelo gpt-3.5-turbo-0613 en los argumentos de ChatOpenAI y recuperarás la clave de API de OpenAI almacenada en los secretos de Streamlit. También establecerás la temperatura en 0 para obtener respuestas más determinísticas (más información aquí).
Para mejorar la calidad de las respuestas de GPT, pasa el siguiente texto al argumento SystemMessage: “Eres un experto útil en finanzas, mercado e investigación de empresas. También tienes habilidades excepcionales en la venta de productos de software B2B”. Esto establecerá los objetivos a seguir por la inteligencia artificial (más información aquí).
from langchain.chat_models import ChatOpenAIfrom langchain.schema import HumanMessage, SystemMessagedef generate_gpt_response(gpt_input, max_tokens): """Función para generar una respuesta de GPT-3. Toma la entrada y el máximo de tokens como argumentos y devuelve una respuesta.""" # Crear una instancia de la clase OpenAI chat = ChatOpenAI(openai_api_key=st.secrets["openai_credentials"]["API_KEY"], model='gpt-3.5-turbo-0613', temperature=0, max_tokens=max_tokens) # Generar una respuesta del modelo response = chat.predict_messages( [SystemMessage(content='Eres un experto útil en finanzas, mercado e investigación de empresas.' 'También tienes habilidades excepcionales en la venta de productos de software B2B.'), HumanMessage( content=gpt_input)]) return response.content.strip()
A continuación, creemos una indicación para el modelo e invoquemos la función generate_gpt_response().
Indica al modelo que cree un análisis FODA de una empresa específica y devuelve el resultado como un diccionario de Python con este código:
input_swot = """Crea un breve análisis FODA de la empresa {name} con ticker {ticker}.Devuelve el resultado como un diccionario de Python con las siguientes claves: Fortalezas, Debilidades, Oportunidades, Amenazas como claves y el análisis como valores.No devuelvas nada más."""input_swot = input_swot.format(name='Empresa 1', ticker='ABC')# devuelve la respuesta de GPT-3gpt_swot = generate_gpt_response(input_swot, 1000)
El diccionario resultante debería verse algo así:
{"Fortalezas": "texto", "Debilidades": "texto", "Oportunidades": "texto", "Amenazas": "texto"}
De manera similar, puedes indicar al modelo GPT que escriba una propuesta de valor para un producto específico de una empresa determinada. La aplicación utiliza el marco de propuesta de valor común que identifica los problemas y beneficios de los clientes, así como los creadores de beneficios y los aliviadores de problemas:
input_vp = """"Crea una breve propuesta de valor utilizando el marco de lienzo de propuesta de valor para {producto} de la empresa {name} con ticker {ticker} que opera en la industria {industria}.Devuelve el resultado como un diccionario de Python con las siguientes claves: Problemas, Beneficios, Creadores de Beneficios, Aliviadores de Problemas como claves y texto como valores. Sé específico y conciso. No devuelvas nada más."""input_vp = input_vp.format(producto='Software de contabilidad', name='Empresa 1', ticker='ABC', industria='Retail')# devuelve la respuesta de GPT-3gpt_value_prop = generate_gpt_response(input_vp, 1000)# la respuesta se ve así: # {"Problemas": "texto", "Beneficios": "texto", "Creadores de Beneficios": "texto", "Aliviadores de Problemas": "texto"}
Extraer datos estructurados de la respuesta de GPT
En el paso anterior, solicitaste al modelo GPT un diccionario de respuestas en Python. Pero como los LLMs a veces pueden producir respuestas sin sentido, es posible que la cadena devuelta no contenga solo el diccionario necesario. En estos casos, es posible que necesites analizar la cadena de respuesta para extraer el diccionario y convertirlo al tipo de diccionario de Python.
Para lograr esto, necesitarás dos bibliotecas estándar: re y ast.
La función dict_from_string() toma la cadena de respuesta del LLM y devuelve un diccionario en este flujo de trabajo:

Aquí está el código:
import reimport astdef dict_from_string(gpt_response): """Función para analizar la respuesta de GPT y convertirla en un diccionario""" # Encuentra una subcadena que comienza con '{' y termina con '}', en varias líneas match = re.search(r'\\{.*?\\}', gpt_response, re.DOTALL) dictionary = None if match: try: # Intenta convertir la subcadena en un diccionario dictionary = ast.literal_eval(match.group()) except (ValueError, SyntaxError): # No es un diccionario return None return dictionaryswot_dict = dict_from_string(gpt_response=gpt_swot)vp_dict = dict_from_string(gpt_response=gpt_value_prop)
Generar diapositivas usando python-pptx
Ahora que tienes los datos, es hora de completar las diapositivas. Utiliza una plantilla de PowerPoint y reemplaza los marcadores de posición con valores reales utilizando la biblioteca python-pptx.
Así es como debería verse la plantilla de diapositiva SWOT:

Para poblar la diapositiva con datos, utiliza la función replace_text(), que toma dos argumentos:
- Un diccionario con marcadores de posición como claves y texto de reemplazo como valores
- Un objeto de diapositiva de PowerPoint
Utiliza la variable swot_dict definida en el paso anterior:
from pptx import Presentationdef replace_text(replacements, slide): """Función para reemplazar texto en una diapositiva de PowerPoint. Toma un dictado de {coincidencia: reemplazo, ...} y reemplaza todas las coincidencias""" # Itera a través de todas las formas en la diapositiva for shape in slide.shapes: for match, replacement in replacements.items(): if shape.has_text_frame: if (shape.text.find(match)) != -1: text_frame = shape.text_frame for paragraph in text_frame.paragraphs: whole_text = "".join(run.text for run in paragraph.runs) whole_text = whole_text.replace(str(match), str(replacement)) for idx, run in enumerate(paragraph.runs): if idx != 0: p = paragraph._p p.remove(run._r) if bool(paragraph.runs): paragraph.runs[0].text = whole_textprs = Presentation("template.pptx")swot_slide = prs.slides[2]# crea el título de las diapositivasswot_title = 'Análisis FODA de {}'.format('Empresa 1')# inicia un diccionario de marcadores de posición y valores a reemplazarreplaces_dict = { '{s}': swot_dict['Fortalezas'], '{w}': swot_dict['Debilidades'], '{o}': swot_dict['Oportunidades'], '{t}': swot_dict['Amenazas'], '{swot_title}': swot_title}# ejecuta la función para reemplazar marcadores de posición con valoresreplace_text(replacements=replaces_dict, slide=swot_slide)
En resumen, la función replace_text() itera sobre todas las formas en una diapositiva, buscando valores de marcadores de posición y los reemplaza con valores del diccionario si se encuentran.
Una vez que todas las diapositivas se hayan llenado con datos o imágenes, el objeto de presentación se guarda como salida binaria y se pasa a st.download_button() para que un usuario pueda descargar un archivo de PowerPoint (lee más aquí).
Esto es cómo debería verse el botón de descarga en la interfaz:

Y aquí está el código:
from pptx import Presentationfrom io import BytesIOfrom datetime import dateimport streamlit as st# crear el nombre de archivofilename = '{name} {date}.pptx'.format(name='Empresa 1', date=date.today())# guardar la presentación como salida binariabinary_output = BytesIO()prs.save(binary_output)# mostrar mensaje de éxito y botón de descargast.success('¡Las diapositivas se han generado! :tada:')st.download_button(label='Haz clic para descargar PowerPoint', data=binary_output.getvalue(), file_name=filename)
Ver la presentación de muestra aquí.
Conclusión
¡Gracias por leer hasta el final! Ahora puedes desarrollar una aplicación de automatización de diapositivas para la investigación de empresas utilizando Streamlit, Snowflake, YahooFinance y LangChain. Espero que hayas encontrado algo nuevo y útil en esta publicación.
Como puedes ver, hay algunas limitaciones en la aplicación. En primer lugar, solo genera investigación sobre empresas públicas. En segundo lugar, el modelo GPT utiliza conocimientos generales sobre un producto, como ChatBot o Software de Contabilidad, para escribir una propuesta de valor. En una aplicación más avanzada, se podría abordar la segunda restricción ajustando el modelo con los datos de tu producto. Esto se puede hacer pasando los detalles de tu producto como una indicación o almacenando estos datos como incrustaciones en una base de datos de vectores (lee más aquí).
Si tienes alguna pregunta o comentario, por favor publícalo en los comentarios a continuación o contáctame en GitHub, LinkedIn o Twitter.
- Un diccionario con marcadores de posición como claves y texto de reemplazo como valores
- Un objeto de diapositiva de PowerPoint
Utiliza la variable swot_dict
definida en el paso anterior: