Cómo crear un Chatbot con Angular, Firebase y Gemini AI
Mayra Rodriguez

1. Abrir proyecto en Stackblitz
Allí presionaremos la opción Fork ubicada arriba a la izquierda, para que nos genere una copia del proyecto de manera online.

2. Crear cuenta en Firebase
Para ello debemos ir al siguiente link: https://firebase.google.com/ e iniciar sesión con una cuenta de Gmail.

Luego seleccionaremos la opción Go To Console (arriba a la derecha) que nos llevará a la vista donde tenemos nuestros proyectos de Firebase, allí seleccionaremos la opción Agregar Proyecto:

Esa opción nos llevará a la siguiente vista, donde crearemos el proyecto:
3. Crear Proyecto En Firebase
El paso 1 de la creación de un proyecto en Firebase nos consultará el nombre de nuestro proyecto:

Luego, deshabilitaremos la configuración de Analytics ya que para efectos del taller no será necesario y le damos en Continuar:

Luego, esperamos mientras se crea el proyecto (puede tardar unos minutos):

Una vez termina su creación se ve de la siguiente manera, allí daremos click en Continuar:

Y así se verá nuestro dashboard del nuevo proyecto:

En dicho dashboard, vamos a seleccionar el botón con los símbolos ****</>
****, ésto nos permitirá crear las credenciales para conectarlo con nuestra app web, y allí nos pedirá registrar el nombre de nuestra aplicación web y haremos click en el botón Registrar app:

El siguiente paso, nos mostrará sobre la instalación de firebase (sin embargo no será necesario por que nuestro proyecto base ya tiene firebase instalado) y luego nos arrojará las credenciales de nuestra app.Éstas credenciales las colocaremos en nuestro proyecto de Angular en el siguiente paso:

4. Configurar Firebase en el Proyecto de Angular
En nuestro proyecto de Stackblitz, si nos redirigimos al archivo environment.ts
ubicado en la carpeta de environments
, así podremos reemplazar la información con las credenciales arrojadas en el paso anterior.

Volveremos a nuestra consola de Firebase, y seleccionaremos la opción que dice Firestore Database dentro del menú Compilación.

****Allí se mostrará la siguiente vista, en la cual seleccionaremos la opción Crear base de datos:

Nos preguntará la ubicación de nuestra BD, la cual dejaremos la opción por defecto y presionaremos Siguiente:

En la siguiente ventana, nos preguntará sobre las Reglas de Seguridad, cómo estamos en modo prueba podemos seleccionar esa opción.
Recuerda utilizar la opción modo de producción cuando se trate de aplicaciones reales que desees publicar en internet.
Y presionamos la opción Crear:

Ahora esperaremos su instalación:

A continuación verás una vista cómo ésta:

Allí, seleccionaremos la opción llamada Iniciar Colección y la llamaremos conversations:

Y crearemos provisionalmente un documento con el campo prompt
, aquí podremos escribir un mensaje. No olvides seleccionar la opción ID automático para que asigne un ID a nuestro documento. Posterior a ello, el botón Guardar, se habilitará y podrás darle click.

Ahora tenemos nuestro primer documento en nuestra BD

Ahora, volvemos a nuestra app de Angular en Stackblitz, allí configuraremos nuestro chat.Lo primero será, en archivo llamado chat.component.ts
insertar el siguiente código:
export class ChatComponent {
promptText = new FormControl('');
status = Status.Pending;
errorMsg = '';
responses: WritableSignal<DisplayMessage[]> = signal([
{
text: "¡Hola!, ¿Cómo puedo ayudarte hoy?",
type: MessageType.Response
}
]);
private changeDetectorRef = inject(ChangeDetectorRef);
private readonly firestore: Firestore = inject(Firestore);
private readonly conversationsCollection = collection(this.firestore, 'conversations');
constructor() { }
async sendMessage(ev: Event) {
ev.preventDefault();
this.scrollToBottom();
if (!this.promptText.value) return;
const prompt = this.promptText.value;
if(!prompt) {
return;
}
this.status = Status.Processing;
this.responses.update(responses => [...responses,{text: prompt,
type: MessageType.Prompt
}])
this.promptText.setValue('');
const docRef = await addDoc(this.conversationsCollection, { prompt });
const destroyFn = onSnapshot(docRef, {
next: snap => {
const conversation = snap.data();
if (conversation && conversation['status']) {
const state = conversation['status']['state'];
switch (state) {
case Status.Complete:
this.status = Status.Complete;
this.responses.update(responses => [...responses,{
text: conversation['response'],
type: MessageType.Response,
}])
this.status = Status.Complete;
this.changeDetectorRef.detectChanges();
destroyFn();
break;
case Status.Processing:
// You can add something here in this state if you need it
break;
case Status.Errored:
this.status = Status.Errored;
destroyFn();
break;
}
this.scrollToBottom();
}
},
error: err => {
this.errorMsg = err.message;
destroyFn();
this.scrollToBottom();
}
})
}
}
scrollToBottom() {
// Use setTimeout to allow DOM updates before scrolling
setTimeout(() => {
window.scrollTo(0, document.body.scrollHeight);
}, 0);
}
Deberás importar las clases que estamos usando, pero para menor complejidad, asegúrate que se vean cómo éstas:
import {
ChangeDetectorRef,
Component,
inject,
signal,
WritableSignal,
} from '@angular/core';
import { FormsModule, FormControl, ReactiveFormsModule } from '@angular/forms';
import { NgClass, NgOptimizedImage } from '@angular/common';
import {
addDoc,
collection,
Firestore,
onSnapshot,
} from '@angular/fire/firestore';
import { MarkdownComponent } from 'ngx-markdown';
No olvides añadir las siguientes interfaces antes del @Component
enum Status {
Pending = 'PENDING',
Processing = 'PROCESSING',
Complete = 'COMPLETED',
Errored = 'ERRORED'
}
enum MessageType {
Prompt = 'PROMPT',
Response ='RESPONSE'
}
interface DisplayMessage {
text: string;
type: MessageType;
}
En el archivo chat.component.html
agregaremos el siguiente código, justo debajo de lo que teníamos previamente:
<section class="conversations">
@for (response of responses(); track response.text) {
<div class="conversations-message"
[ngClass]="response.type === 'RESPONSE' ? 'conversations-response' : 'conversations-prompt'">
@if(response.type === 'RESPONSE') {
<span
class="chatbot-emoji">
🤖
</span>
}
<markdown class="markdown" [data]="response.text"></markdown>
</div>
} @empty {
<p>No hay mensajes.</p>
}
@if(status === 'PROCESSING') {
<p class="loader"></p>
}
</section>
<section class="prompt-area">
<form class="prompt-form" (ngSubmit)="sendMessage($event)">
<input class="prompt-input" type="text" placeholder="¿Qué debo pagar hoy?" [formControl]="promptText">
<button [disabled]="promptText.value === ''" class="prompt-send-button">▶</button>
</form>
</section>
Hasta éste punto tu aplicación deberá poder enviar mensajes al Firestore en Firebase.
Podrás verificarlo enviando un mensaje, y validando que su creación fué exitosa en Firestore.


Pero nos falta lo más importante… la Inteligencia Artificial…
5. Instalación de Gemini en Firebase
En la consola de Firebase, iremos a la opción que dice Extensions dentro del menú Compilación.

Al dar click en Extensions nos muestra las diferentes extensiones que podemos usar, en nuestro caso, buscamos la que dice Build Chatbot with the Gemini API y presionaremos Instalar:

Ésto nos redirigirá a la siguiente vista, en donde seleccionaremos una opción que se muestra más abajo llamada Actualizar proyecto para continuar:

Allí seleccionaremos la Cuenta de Facturación creada en el primer paso del workshop, seleccionar dicha opción y luego Continuar.

Colocaremos un presupuesto de 5 USD y presionamos continuar.

Y seleccionamos la opción Comprar:

Deberá aparecerte el siguiente mensaje, podremos cerrarla y continuar:

Deberemos Habilitar las siguientes opciones

Luego, se habilitará el botón de Siguiente para continuar.

Nuevamente presionamos Siguiente:

Y ahora nos pide configurar nuestra extensión:

Allí cambiaremos la siguiente información:
- Gemini API Provider seleccionaremos la opción Vertex AI
- Firestore Collection Path y colocaremos
conversations
(el nombre de nuestra colección en Firestore). - Cloud Functions Location, la opción de lowa (us-central1).
Luego presionaremos la opción de Instalar la extensión.Allí esperaremos unos minutos mientras se instala…

Y luego haremos click en Comenzar:

Aquí veremos cómo podemos probar dicha extensión en nuestro proyecto web, sin embargo, nosotros/as ya lo tomamos en cuenta en pasos anteriores.

Para probar que nuestra extensión funciona correctamente, podemos ir a Firestore, prueba presionando en el botón de Agregar Documento y agregarle al documento un parámetro llamado prompt
con un saludo cómo: “Hola cómo estás?” y verás que en cuestión de segundos Gemini generará la respuesta.

Si probamos en nuestra app de Stackblitz también debería estar funcionando!
6. Contexto de la Información
Ya tenemos nuestra aplicación conectada exitosamente con Firebase y Gemini, más sin embargo, todavía nos falta algo.Éste chatbot, más allá de interactuar con la AI de Gemini, también debería arrojarme información relacionada con mis finanzas ¿correcto?, pero para ello debemos suministrarle dicha información.Para ello, vamos a ir al siguiente link donde tenemos un archivo Google Datasheet de ejemplo:https://docs.google.com/spreadsheets/d/1_329qUJeXHYlip1V_9np7HPF0m1rdpZkOBk8S-jfUsA/edit?usp=sharingY vamos a exportarlo en formato csv
, el cual es un archivo que contiene toda la información separada por comas.

Y vamos a escribir el siguiente prompt
en un archivo de notas:
Answers the questions based on the information in the CSV below: "<Inserta aquí el contenido del csv>
" Please note the answers must be given in Spanish, the Amount value is Colombian pesos and the date is in the format YYYY-MM-DD
Debería verse así:Answers the questions based on the information in the CSV below: "Bills,Amount,DueTime TV,250000,2024-04-01 Teléfono,65000,2024-04-26 Luz,300000,2024-03-15 Agua,10000,2024-01-01 Gas,75000,2024-02-15 Internet,50000,2024-05-10 Colegio (Juan),200000,2024-04-15 Colegio (María),150000,2024-04-15 Gimnasio,80000,2024-05-05 Supermercado,120000,2024-04-07 Restaurante,50000,2024-04-14 Cine,30000,2024-04-20 Transporte público,25000,2024-04-30 Ropa,100000,2024-05-02 Regalos,75000,2024-05-15 Alquiler,600000,2024-05-01 Impuestos,350000,2024-06-15 Médico,150000,2024-04-25 Dentista,80000,2024-05-08 Veterinario,50000,2024-04-22 Reparación auto,200000,2024-05-12 Seguro auto,100000,2024-06-01 Viaje,500000,2024-07-01 Ahorro,200000,2024-05-31" Please note the answers must be given in Spanish, the Amount value is Colombian pesos and the date is in the format YYYY-MM-DD
Copiamos el texto anterior completo y vamos a crear un documento en nuestra colección de Firebase, cómo lo hemos hecho previamente, con ésto le estamos dando indicaciones a Gemini sobre la información que queremos consultar, es decir, el contexto.Y si le preguntamos a la AI, algo relacionado, por ejemplo: ¿Cuales son las facturas por pagar en Abril?, podrá arrojarnos la respuesta:

Y con ésto habremos concluído el taller.