El otro día, en otra noche de insomnio, me encontré con un post de Brian Julius (aquí os dejo el enlace a su perfil de LinkedIn https://www.linkedin.com/in/brianjuliusdc/) , en el que había adaptado una métrica DAX con las funciones INFO.VIEW (que ya sabéis lo que me gustan) y era válida para cualquier modelo. El objetivo es preguntar a cualquier IA información completa sobre el modelo de datos. 
 

La métrica en cuestión era la siguiente:

BIM Info =

// Autor métrica: Brian Julius

VAR TableInfo =

    ADDCOLUMNS (

        INFO.VIEW.TABLES (),

        "Component", "Tables"

    )

VAR ColumnInfo =

    ADDCOLUMNS (

        INFO.VIEW.COLUMNS (),

        "Component", "Columns"

    )

VAR RelationshipInfo =

    ADDCOLUMNS (

        INFO.VIEW.RELATIONSHIPS (),

        "Component", "Relationships"

    )

VAR MeasureInfo =

    ADDCOLUMNS (

        INFO.VIEW.MEASURES (),

        "Component", "Measures"

    )

VAR Result =

    TOCSV ( TableInfo )

        & TOCSV ( ColumnInfo )

        & TOCSV ( RelationshipInfo )

        & TOCSV ( MeasureInfo )

 

RETURN

    Result

 
Esta métrica lo que hace es obtener toda la información relativa al modelo semántico de Power BI con las funciones INFO.VIEW y luego las une todas en un CSV para obtener la información y poder preguntarle a cualquier IA información sobre nuestro modelo. ¿Y por que las pasa todas a un CSV? Por que no podemos usar la función UNION ya que no todas las tablas tienen el mismo número de columnas. Antes de seguir, si no sabéis que son las funciones INFO.VIEW, aquí os dejo el enlace al post en que hablo de ellas.

Bien, ahora que habéis refrescado la memoria de las funciones INFO.VIEW, podemos meternos en “harina” como se suele decir.

Tenemos el siguiente “Panel de control” del modelo semántico que se alimenta de las funciones INFO.VIEW.XXXX():

 

  

Vemos que tenemos debidamente documentado nuestro modelo semántico, tanto las descripciones de las medidas, columnas y tablas. Algo que nos facilita mucho las vistas TMDL+VSC+Copilot (aquí el post). Con este informe que llamamos panel de control, tenemos una vista un “pelín” técnica de nuestro modelo semántico. Pero… ¿qué ocurre si queremos una descripción menos técnica, que nos detecte puntos débiles de nuestro modelo, así como nos ofrezca posibles mejoras de rendimiento o propuestas de valor para el modelo que no hemos detectado? Aquí es donde entra en acción Brian Julius con su métrica.

Si vamos a la vista de consultas DAX y pegamos la métrica anterior, obtenemos:


Un error, ¿por qué? Por qué “Result” no es una expresión tipo tabla. Para solucionarlo podemos hacer 3 opciones:

  • Llamar a nuestro vecino para que nos la arregle.
  • Modificar la expresión completa para adaptarla.
  • Envolver con {} Result de manera que lo convirtamos en salida tipo tabla.

Yo opto por la tercera opción ya que es más rápida y sencilla para este caso:


 

Vemos que nos devuelve una tabla de una única columna y fila, con un montón de valores separados por comas:

 

Copiamos el valor devuelto y vamos a Copilot, ChatGPT o a la IA que queramos, le pegamos dicha información con un prompt similar al siguiente:

“Como experto en el modelo tabular, te copio información sobre mi modelo de datos de Power BI. Explicame de manera clara y precisa todo lo que puedas saber del modelo semántico: (y aquí pegamos el valor devuelto por la métrica anterior)”

 

Y nos devuelve lo siguiente (son pantallazos de lo que ha devuelto ChatGPT en este caso y no son todos):

 

 

 

 

 

 

 

 


¿Cómo os quedáis? Yo cuando lo ví, dije: “Wauu”. Pero a la vez me hizo pensar (sí, raro en mí ya lo sé pero por una vez que piense no pasa nada ¿no?) Me hice las siguientes preguntas:

El potencial que tiene es espectacular pero esto es sólo la punta del iceberg.
 

  • Me está devolviendo las tablas de control que tengo. ¿Las puedo quitar?
  • ¿Qué pasaría si integrásemos todo en el reporte de Power BI?”


La respuesta a la primera pregunta es “Sí, sí se puede” y lo hice adaptando la métrica de Brian Julius a mi modelo y nomenclatura:

 

BIM_Info_Table =

VAR ExcludedTables =

    FILTER(

        INFO.VIEW.TABLES(),

        NOT LEFT([Name], 5) = "Tabla" // Excluye tablas cuyo nombre empieza con "Tabla" ya que todas las tablas de las funciones INFO.VIEW comienzan “Tabla”

    )

 

// Normalizamos la estructura para que todas las tablas tengan las mismas columnas

VAR TableInfo =

    SELECTCOLUMNS(

        ExcludedTables,

        "Nombre", [Name], // Nombre de la tabla

        "Tipo", "Table", // Indica que es una tabla

        "Tabla de Origen", BLANK(),

        "Dato Relacionado", BLANK(),

        "Expresión", BLANK(),

        "Descripción", [Description] // Descripción de la tabla

    )

 

VAR ColumnInfo =

    SELECTCOLUMNS(

        EXCEPT(

            INFO.VIEW.COLUMNS(),

            FILTER(INFO.VIEW.COLUMNS(), LEFT([Table], 5) = "Tabla")

        ),

        "Nombre", [Name], // Nombre de la columna

        "Tipo", "Column", // Indica que es una columna

        "Tabla de Origen", [Table], // Tabla a la que pertenece la columna

        "Dato Relacionado", BLANK(),

        "Expresión", BLANK(),

        "Descripción", [Description] // Descripción de la columna

    )

 

VAR RelationshipInfo =

    SELECTCOLUMNS(

        EXCEPT(

            INFO.VIEW.RELATIONSHIPS(),

            FILTER(INFO.VIEW.RELATIONSHIPS(), LEFT([FromTable], 5) = "Tabla" || LEFT([ToTable], 5) = "Tabla")

        ),

        "Nombre", BLANK(), // Las relaciones no tienen un nombre específico

        "Tipo", "Relationship", // Indica que es una relación

        "Tabla de Origen", [FromTable], // Tabla de origen de la relación

        "Dato Relacionado", [ToTable], // Tabla de destino de la relación

        "Expresión", [Relationship],

        "Descripción",  [CrossFilteringBehavior] & " - " & [IsActive]

    )

 

VAR MeasureInfo =

    SELECTCOLUMNS(

        EXCEPT(

            INFO.VIEW.MEASURES(),

            FILTER(INFO.VIEW.MEASURES(), LEFT([Table], 5) = "Tabla")

        ),

        "Nombre", [Name], // Nombre de la medida

        "Tipo", "Measure", // Indica que es una medida

        "Tabla de Origen", [Table], // Tabla a la que pertenece la medida

        "Dato Relacionado", BLANK(),

        "Expresión", [Expression], // Código DAX de la medida

        "Descripción", [Description] // Descripción de la medida

    )

 

// Unimos todas las tablas en una única tabla con la misma estructura

RETURN

    UNION(

        TableInfo,

        ColumnInfo,

        RelationshipInfo,

        MeasureInfo

    )

Si os dais cuenta, una pequeña diferencia entre la métrica original y esta, es que selecciono las columnas de las diferentes tablas con el objetivo de que todas las tablas tengan el mismo número de columnas para poder usar la función UNION. Esta expresión me devuelve una tabla con 6 columnas:

 

Por otro lado, esta métrica la convierto en tabla, es decir, materializo una tabla en mi modelo de datos llama BIM_Info_Table. Y diréis, ¿por qué hago una tabla si la medida es mejor? Estamos de acuerdo, pero si quiero ejecutar una consulta DAX mediante Power Automate, las funciones INFO ya no están disponibles por seguridad, por lo que materializo una tabla con las funciones INFO, y desde Power Automate lanzo la consulta de la tabla (no de las funciones INFO).

Una vez hecho el paso anterior, empecé a trastear y llegue a la siguiente infraestructura:

 

 

Tenemos un origen de datos diverso. Un informe en Power BI con un flujo de Power Automate que lanza la consulta a ChatGPT vía API, este nos devuelve la respuesta a la pregunta y el mismo flujo guarda la respuesta en origen para integrarlo dentro del propio informe de manera automática... Y hasta aquí puedo escribir, el resto me lo guardo para mí… ¡Es broma! ¿Cómo voy a dejaros con la duda? 
 
Lo primero que hacemos es sacar un botón de Power Automate al informe:
 
 
 
Una vez tenemos el botón de Power Automate, se nos abre en el informe el siguiente objeto visual:
 
 
 
Lo primero seleccionamos el entorno donde vamos a desplegar el flujo de datos arriba a la derecha. A continuación pasamos el cursor sobre el objeto y hacemos clic sobre los tres puntitos que nos aparecen:
 

 Y hacemos clic en “Editar”:

 
Y se nos abre Power Automate en Power BI y podemos empezar a crear un flujo:
 
 
 
 Hacemos clic en “Nuevo” y luego en “Flujo de nube instantánea”:
 
 
 
 
Y de manera automática se nos genera el un desencadenador, que va a ser el encargado de activar/disparar el flujo, en este caso, es un botón en el informe:
 
 
 
 
Añadimos un nuevo paso que es “Ejecutar una consulta con un conjunto de datos”:
 
 
 
 

Y rellenamos los campos área de trabajo, el conjunto de datos y el texto de la consulta. Como podéis ver, estamos ejecutando una simple consulta EVALUATE a la tabla que hemos creado previamente. Importante, el informe tiene que estar publicado en el servicio de Power BI.

A continuación, añadimos un nuevo paso, que en este caso es HTTP (es un conector premium eso sí…). Seleccionamos el método que vamos a usar, que es “POST” ¿Por qué? Porque vamos a mandar (o por lo menos intentarlo 😊) a ChatGPT el mensaje del que queremos respuesta.

En el segundo paso, URI, introducimos lo siguiente:
 
Y a continuación en los encabezados escribimos lo siguiente:
 
 
 
 
Y es todo por hoy... ¡que no! Continua aquí en el siguiente post.

¡Nos vemos en los datos!