
Food Fit: tu partner para tener una alimentación saludable con Genkit 🍎
En esta guía, aprenderás a construir una aplicación web con Genkit, Gemini 2.0 Flash e Imagen 3, para generar recetas saludables y desplegarla en Firebase.
¿Qué es Genkit?
Genkit es el framework desarrollado por Google para construir aplicaciones potenciadas por IA. Está diseñado para funcionar con muchos proveedores de modelos de IA y bases de datos vectoriales.
¿Qué es Gemini 2.0 Flash?
Gemini 2.0 Flash es un modelo multimodal de tamaño mediano que está optimizado para una amplia variedad de tareas de razonamiento.
¿Qué es Imagen 3?
Es el modelo de generación de imágenes de Google, que se puede usar para la creación de imágenes a partir de un texto.
Ahora que sabemos qué herramientas utilizaremos, veamos cómo se integran en la arquitectura de nuestra aplicación.

La aplicación que crearemos la desplegaremos en Firebase Hosting aprovechando los diferentes servicios que tiene Firebase. Para el backend, usaremos Cloud Functions, que nos permite crear rápidamente una función e implementarlo con los flujos (flows en inglés) de Genkit. Por último, implementaremos Imagen 3 y Gemini 2.0 Flash para generar el contenido.
En Genkit, un ‘flow’ es un flujo de generación de contenido basado en IA. Definiremos tres: uno para sugerir recetas, otro para listar opciones y otro para generar imágenes de los platillos.
Pasos para construir la aplicación
Crear el proyecto en la consola de Firebase.
Como lo comenté líneas arriba, usaremos Cloud Functions, y es un servicio que requiere cambiar al plan de pago (Blaze), sin embargo, si no excedemos la cuota, no generaremos ningún gasto.
Recuerda agregar siempre alertas de facturación para controlar el uso de la nube. Tengo un artículo donde explico acerca de la facturación de Google Cloud Platform.

Después de eso, sigue crear el proyecto e instalar las dependencias de Genkit. Para evitar repetir este paso en cada proyecto con Genkit, he creado un boilerplate que ya tiene las dependencias necesarias para levantar el proyecto.
Si tienes alguna duda sobre el boilerplate, me puedes dejar un comentario o escribirme por X.
Para utilizar la API de Gemini, necesitarás una clave de API. Si aún no tiene una, cree una clave en Google AI Studio.
Además, recuerda habilitar el API de Vertex AI para poder usarlo en nuestro proyecto.

Luego de configurar el API en el proyecto, al levantar el proyecto de forma local se mostrará lo siguiente:

Iremos al archivo index.ts y pegaremos el siguiente código:
require('dotenv').config();
import { z, genkit } from 'genkit';
import { gemini20Flash001, imagen3, vertexAI } from '@genkit-ai/vertexai';
// Construimos los esquemas que nos ayudarán para tener una estructura de salida en cada flujo.
const outputFoodItemSchema = z.object({
name: z.string(),
description: z.string(),
ingredients: z.array(z.string()),
nutritional_information: z.object({
cal: z.number(),
carbohydrates: z.number(),
fats: z.number(),
sodium: z.number(),
cholesterol: z.number(),
proteins: z.number(),
}),
preparation_time: z.string(),
level: z.string(),
preparation: z.array(z.string()),
});
const inputSchema = z.object({
ingredient: z.string(),
quantity_people: z.number()
});
// Configuramos Genkit
const ai = genkit({
plugins: [
vertexAI({ location: 'us-central1' }),
],
});
// Creamos los flujos
export const foodSuggestionFlow = ai.defineFlow(
{
name: 'foodSuggestionFlow',
inputSchema: inputSchema,
outputSchema: z.array(outputFoodItemSchema),
},
async (payload) => {
const { output } = await ai.generate({
model: gemini20Flash001,
prompt: `
Eres el asistente de inteligencia artificial más experto en gastronomía.
Genera un lista de 4 recetas para una persona que quiere alimentarse de forma saludable.
En la matriz de las recetas, coloque las recetas como lo haría un recetario de comida.
Las recetas deben contener ${payload.ingredient} como ingrediente principal.
Dale a cada receta una descripción única.
Las recetas deben ser saludables y equilibradas. Además que sean para ${payload.quantity_people} personas.
Las recetas tienen que estar en español.
Limite las descripciones de las recetas a 7 palabras.
`,
output: { schema: z.array(outputFoodItemSchema) }
});
if (output == null) {
throw new Error("Response doesn't satisfy schema.");
}
return output;
}
);
export const listFoodsSuggestionFlow = ai.defineFlow(
{
name: 'listFoodsSuggestionFlow',
outputSchema: z.array(outputFoodItemSchema),
},
async () => {
const { output } = await ai.generate({
model: gemini20Flash001,
prompt: `Eres el asistente de inteligencia artificial más experto en gastronomía.
Genera un lista de 4 recetas para una persona que quiere alimentarse de forma saludable.
En la matriz de las recetas, coloque las recetas como lo haría un recetario de comida.
Dale a cada receta una descripción única.
Las recetas deben ser saludables y equilibradas. Además que sean para 4 personas.
Las recetas tienen que estar en español.
Limite las descripciones de las recetas a 7 palabras.`,
output: { schema: z.array(outputFoodItemSchema) }
});
if (output == null) {
throw new Error("Response doesn't satisfy schema.");
}
return output;
}
);
export const generateImageFoodFlow = ai.defineFlow(
{
name: 'generateImageFoodFlow',
inputSchema: z.object({
food: z.string(),
})
},
async (payload) => {
const response = await ai.generate({
model: imagen3,
prompt: `Photo of the Peruvian dish ${payload.food}`,
output: { format: 'media' },
});
if (response == null) {
throw new Error("Response doesn't satisfy schema.");
}
return response.message.content[0].media;
}
);
Y veremos que en la UI de Genkit, aparecerán los flujos creados: foodSuggestionFlow, listFoodsSuggestionFlow y generateImageFoodFlow.

- foodSuggestionFlow: Es el flujo creado para sugerir platos saludables pasándole como parámetro un alimento y la cantidad de personas.
- listFoodsSuggestionFlow: Es el flujo creado para sugerir platos saludables.
- generateImageFoodFlow: Es el flujo creado para generar la imagen del plato a partir del nombre.
Podemos usar el dashboard para probar el flujo y su respuesta. Además, hacer un seguimiento del flujo y ver si algo falló.

Adjunto el proyecto donde se encuentra un archivo llamado index.local.ts donde está la configuración completa. Recuerda actualizar tu API KEY.
Ahora que tenemos nuestros flujos creados, procedemos a crear los Cloud Functions, donde agregaremos las dependencias firebase-functions y agregaremos un pequeño código a nuestros flujos.
Ya definimos el flujo foodSuggestionFlow para generar recetas saludables. Ahora lo integraremos con Firebase Functions para poder consumirlo desde nuestra aplicación.
export const foodSuggestionFlowFunction = onCallGenkit({
authPolicy: () => true,
secrets: [googleAIapiKey],
cors: '*'
}, foodSuggestionFlow);
Creamos una función llamada foodSuggestionFlowFunction donde uso el método onCallGenkit para hacer una configuración de la función en la nube y pasarle nuestro flujo foodSuggestionFlow.
Al desplegar las Cloud Functions en Firebase, podremos verlo desde el dashboard de Firebase.

Luego, solo quedará obtener la data haciendo la solicitud desde la aplicación de Angular.

Dejo el repositorio completo con los flujos completos, las funciones de la nube y la configuración del proyecto.
Además, dejó el resultado final del proyecto.
Aprovecharé la aplicación y buscaré una receta para cenar. 🥗 Si te interesa aprender más sobre Genkit y Vertex AI, puedes dejarme un comentario con tus dudas.
Google Cloud credits are provided for this project. #VertexAISprint