Crea tu propio chat de cocina con Next.js, Project IDX y Firebase: una guía paso a paso

Vanessa Marely Aristizabal Angel
7 min readJul 23, 2024

--

Cooking Chat, imagen generada en DAL-E

En este artículo, les mostraré cómo construir un chat interactivo especializado en cocina utilizando Next.js, el potente framework de React. Aprovecharemos las herramientas de Google, como Project IDX para el desarrollo y Firebase para el alojamiento, y conectaremos nuestro chat a una API personalizada creada con MakerSuite. ¡Prepárense para llevar sus conversaciones culinarias al siguiente nivel!

Paso 1: Configuración Inicial en Project IDX

  1. Crear Workspace:
Captura del ambiente del Project IDX
  • Accede a Project IDX y crea un nuevo workspace.
  • Selecciona “Web” como plataforma y elige “Next.js” como framework.
  • Nombra tu workspace (por ejemplo, “chat-cocina-nextjs”) y sigue los pasos de configuración para tu proyecto en nextt.js, de acuerdo a tus preferencias.
Captura del Hola mundo de Next.js en Project IDX

2. Copiar la API de MakerSuite:

  • Genera tu API de chat en MakerSuite y copia la URL base.
Generar clave en Maker Suite
  • En Project IDX, crea un archivo .env.local en la raíz de tu proyecto.
  • Agrega la siguiente línea, reemplazando con tu URL real:
NEXT_PUBLIC_API_BASE_URL=TU_URL_BASE_DE_API_AQUÍ

Paso 2: Estructura del Chat de Cocina en Next.js

  1. Crear Componentes:

Crea los componentes necesarios para tu aplicación:

  • CookingChat.js: Componente para el manejo del chat
  • Loading.js: Componente para el spinner o loading de nuestro chat. (Este componente es opcional).
"use client";

import Head from "next/head";

export default function CookingChat() {
return (
<>
<Head>
<title>Cooking Chat</title>
</Head>
<div className="bg-gray-100">
<form>
<label
htmlFor="message"
className="block text-gray-700 text-sm font-bold mb-2"
>
Your Message
</label>
<textarea
id="message"
rows="3"
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="I am AI model, expert cooking assistant. Ask me anything about cooking!"
></textarea>
<button
className="mt-3 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Send
</button>
</form>
</div>
</>
);
}

Nota: Adecua tu proyecto de acuerdo a tus necesidades, adiciona autenticación si deseas u otros componentes. Puedes seguir las recomendaciones de la página oficial de Next.js para darle estructura a tus archivos https://nextjs.org/docs/getting-started/project-structure

Paso 3: Consumir la API de MakerSuite

Para usar exitosamente la API de Gemini, debemos hacer la instalación de la librería en la terminal de IDX:

npm install @google/generative-ai
Captura de la terminal en el Project IDX
  • Dentro de tu componente CookingChat, importa los módulos necesarios e inicializa la conexión con Gemini y crea algunas constantes para definir el modelo y algunos parámetros de seguridad
import {
GoogleGenerativeAI,
HarmBlockThreshold,
HarmCategory,
} from "@google/generative-ai";

// safety settings for the model
const safetySettings = [
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
},
{
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
},
{
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
},
{
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
},
];

// generation config for the model
const generationConfig = {
temperature: 1,
topP: 0.95,
topK: 64,
maxOutputTokens: 8192,
responseMimeType: "text/plain",
};

const MODEL_NAME = "gemini-1.5-flash";
const API_KEY = process.env.NEXT_PUBLIC_API_KEY;

Añadiremos el código necesario para manejar los eventos que controlaran el botón y el campo de texto. Además de la lógica para manejar la funcionalidad del chat que instanciará la API de Gemini.

export default function CookingChat() {
const [loading, setLoading] = useState(false);
const [chatHistory, setChatHistory] = useState([{ parts: "", role: "" }]);
const [message, setMessage] = useState(
" You are an expert AI cooking model, I want to prepare a dish, for example a pizza, can you help me with the recipe?"
);

const genAI = new GoogleGenerativeAI(API_KEY);

const chat = model.startChat({
history: [],
});

const addMessageToHistory = (role, message) => {
setChatHistory((prev) => [...prev, { parts: message, role }]);
};

const fetchData = async () => {
setLoading(true);
addMessageToHistory("user", message);
const result = await chat.sendMessage(message);
const response = result.response
.text()
.replace(/\*\*/g, "<b>")
.replace(/\*/g, "<li>")
.replace(/\_/g, "<i>")
.replace(/\n/g, "<br>");
addMessageToHistory("model", response);
setMessage("");
setLoading(false);
};

const handleSubmit = async (event) => {
event.preventDefault();
fetchData();
};

const handleSetMessage = (event) => {
setMessage(event.target.value);
};

return (
<>
<Head>
<title>Cooking Chat</title>
</Head>
<div className="bg-gray-100">
<div className="container mx-auto p-4">
<div className="bg-white rounded-lg p-4">
<div className="mb-4">
<h2 className="text-xl font-semibold">Chat</h2>

{loading && <Loading />}
<div className="border-t-2 border-gray-200 mt-2 pt-2">
{chatHistory.map(({ parts, role }, index) => (
<div className="flex items-start mb-4 text-sm" key={index}>
{parts.length > 0 ? (
<div className="flex-1 ml-3 pt-1">
<p className="text-gray-600">
{role === "user" ? (
<span>User</span>
) : (
<span>Model:</span>
)}
</p>
<div dangerouslySetInnerHTML={{ __html: parts }} />
</div>
) : null}
</div>
))}
</div>
</div>
<div className="mt-4">
<form onSubmit={handleSubmit}>
<label
htmlFor="message"
className="block text-gray-700 text-sm font-bold mb-2"
>
Your Message
</label>
<textarea
id="message"
rows="3"
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="I am AI model, expert cooking assistant. Ask me anything about cooking!"
value={message}
onChange={handleSetMessage}
></textarea>
<button
className="mt-3 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Send
</button>
</form>
</div>
</div>
</div>
</div>
</>
);
}

Puedes ver el repositorio del proyecto aquí:

Paso 4: Diseño y Maquetación

  • Utiliza componentes de interfaz de usuario (por ejemplo, de Material UI o Chakra UI) para crear el diseño del chat, para este chat usé Tailwind.
  • Personaliza los estilos según la temática de cocina.

Paso 5: Hostear en Firebase Hosting (Directamente desde Project IDX)

  1. Conectar a Firebase:
Conectarse a Firebase
  • En Project IDX, ve a la sección “Firebase” en la barra lateral.
  • Haz clic en “Connect to Firebase” y sigue las instrucciones para vincular tu proyecto de Firebase.
Firebase Hosting

Al dar clic en autenticar, te preguntará si deseas compartir información de reporte de información.

Autenticación en la Terminal

Luego en la terminal se debe seguir las siguientes instrucciones:

Intrucciones en la terminal

Permite que el CLI se vincule a tu cuenta de Gmail y una vez lo hagas se mostrará los siguientes pasos:

Logueo en Firebase primer paso

Una vez aceptes el primer paso, confirmará el session ID.

Logueo en Firebase segundo paso

Y luego te genera un código de autorización.

Logueo en Firebase tercer paso

Al copiar el código en la terminal quedarás exitosamente logueado.

Mensaje de logueo exitoso

Una vez logueado, se procede a inicializar el Firebase Hosting.

Project setup

Podemos seleccionar un proyecto creado previamente en la consola de Firebase o crear uno nuevo.

Si seleccionamos crear uno nuevo aparecerá la siguiente información:

Crear un nuevo proyecto

Podemos crear el proyecto en la consola de Firebase y seguimos los pasos hasta que nuestro proyecto esté creado.

Crea un proyecto

Podemos seleccionar un proyecto existente desde la terminal de IDX.

Project setup en Terminal

Nos pregunta si deseamos usar el código existente.

Hosting setup en Terminal

Seleccionamos la región, y se inicializará Firebase.

Setup en la Terminal

2. Desplegar

  • Una vez conectado, haz clic en el botón “Deploy” en la sección de Firebase de Project IDX.
  • Project IDX se encargará de construir y desplegar tu aplicación en Firebase Hosting automáticamente.
Workspace en Project IDX

Al hacer el deploy a producción en la consola de Firebase podemos ver los dominios generados, donde podremos revisar nuestra aplicación.

Dominios en Firebase
Aplicación Web del chat

Te comparto los slides de una charla relacionada con este artículo. Charla que compartí en el Google i/o extended en Cali.

Recursos

--

--