Codea Bien Logo
Construye Apps con IA en Angular usando Genkit y Gemini
Angular

Construye Apps con IA en Angular usando Genkit y Gemini

Kevin Dávila

angulargeminigenkit

Hace poco estuve probando con la nueva seccion "Build with AI" de Angular y me gustó bastante. Angular ahora tiene integracion oficial para construir aplicaciones impulsadas por AI.

Si antes necesitabas ser un experto en machine learning para integrar IA en tu app web, ahora con Genkit, Firebase AI Logic y la Gemini API, cualquier desarrollador Angular puede crear experiencias inteligentes.


Las tres opciones que ofrece Angular

1. Genkit (Full-stack)

Genkit es un toolkit open-source de Google para construir features de IA en apps web y mobile. Lo mejor: es model-agnostic, asi que puedes usar Gemini, OpenAI, Anthropic u Ollama.

Ideal para: aplicaciones full-stack con logica de IA compleja en el servidor, como recomendaciones personalizadas.

"Genkit gives you the choice of supported models and interface with a unified API for building full-stack applications" - Source: https://angular.dev/ai

2. Firebase AI Logic (Client-side)

Firebase AI Logic proporciona una forma segura de interactuar con Vertex AI Gemini API directamente desde el navegador. No necesitas servidor.

Ideal para: features de IA directamente en el browser, como chatbots basicos o analisis de texto en tiempo real.

3. Gemini API (Directo)

Acceso directo a los modelos de Google con soporte para audio, imagenes, video y texto.

Ideal para: aplicaciones que necesitan control total sobre los modelos, como generacion personalizada de imagenes.


Tutorial: App agentic con Genkit y Angular

Vamos a construir algo real. Un asistente que pueda usar "tool calling" para ejecutar acciones en tu aplicacion.

Paso 1: Setup del proyecto

# terminal
ng new ai-assistant --ssr
cd ai-assistant
npm install genkit @genkit-ai/google-genai

Paso 2: Configurar Genkit en el servidor

// src/server/ai.ts
import { genkit } from 'genkit';
import { googleAI, gemini25Flash } from '@genkit-ai/google-genai';

export const ai = genkit({
  plugins: [googleAI()],
  model: gemini25Flash,
});

Paso 3: Definir un flow con tool calling

// src/server/flows/chat.flow.ts
import { ai } from '../ai';
import { z } from 'zod';

const inventoryTool = ai.defineTool(
  {
    name: 'checkInventory',
    description: 'Check product inventory availability',
    inputSchema: z.object({
      productName: z.string().describe('Name of the product to check'),
    }),
    outputSchema: z.object({
      available: z.boolean(),
      quantity: z.number(),
    },
  },
  async ({ productName }) => {
    // Simulacion - en produccion consultarias tu DB
    const inventory: Record<string, { available: boolean; quantity: number }> = {
      'laptop': { available: true, quantity: 15 },
      'mouse': { available: true, quantity: 200 },
      'monitor': { available: false, quantity: 0 },
    };
    return inventory[productName.toLowerCase()] ?? { available: false, quantity: 0 };
  }
);

export async function chatWithAssistant(userMessage: string) {
  const result = ai.generate({
    prompt: &#96;You are a helpful store assistant. Answer the user's question about products.
    
    User: &#36;{userMessage}&#96;,
    tools: [inventoryTool],
  });

  return result.text;
}

Paso 4: Crear el endpoint del servidor

// src/server/routes/chat.ts
import { Router } from 'express';
import { chatWithAssistant } from '../flows/chat.flow';

const router = Router();

router.post('/api/chat', async (req, res) => {
  try {
    const { message } = req.body;
    const response = await chatWithAssistant(message);
    res.json({ response });
  } catch (error) {
    res.status(500).json({ error: 'Something went wrong' });
  }
});

export default router;

Paso 5: El componente Angular

// src/app/chat/chat.component.ts
import { Component, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-chat',
  template: &#96;
    <div class="chat-container">
      <div class="messages">
        @for (msg of messages(); track msg.id) {
          <div class="message" [class.user]="msg.isUser">
            {{ msg.text }}
          </div>
        }
      </div>
      <div class="input-area">
        <input
          #input
          type="text"
          placeholder="Ask about our products..."
          (keyup.enter)="sendMessage(input.value); input.value = ''"
        />
        <button (click)="sendMessage(input.value); input.value = ''">
          Send
        </button>
      </div>
    </div>
  &#96;,
  styles: &#96;
    .chat-container {
      max-width: 600px;
      margin: 2rem auto;
      border: 1px solid #e0e0e0;
      border-radius: 8px;
      overflow: hidden;
    }
    .messages {
      height: 400px;
      overflow-y: auto;
      padding: 1rem;
    }
    .message {
      padding: 0.5rem 1rem;
      margin: 0.5rem 0;
      border-radius: 16px;
      background: #f0f0f0;
      max-width: 80%;
    }
    .message.user {
      background: #007bff;
      color: white;
      margin-left: auto;
    }
    .input-area {
      display: flex;
      padding: 1rem;
      border-top: 1px solid #e0e0e0;
    }
    input {
      flex: 1;
      padding: 0.5rem;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      margin-left: 0.5rem;
      padding: 0.5rem 1rem;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
  &#96;,
})
export class ChatComponent {
  private http = inject(HttpClient);

  messages = signal<Array<{ id: number; text: string; isUser: boolean }>>([]);
  private nextId = 0;

  sendMessage(text: string) {
    if (!text.trim()) return;

    this.messages.update((msgs) => [
      ...msgs,
      { id: this.nextId++, text, isUser: true },
    ]);

    this.http.post<{ response: string }>('/api/chat', { message: text }).subscribe({
      next: (res) => {
        this.messages.update((msgs) => [
          ...msgs,
          { id: this.nextId++, text: res.response, isUser: false },
        ]);
      },
      error: () => {
        this.messages.update((msgs) => [
          ...msgs,
          { id: this.nextId++, text: 'Sorry, something went wrong.', isUser: false },
        ]);
      },
    });
  }
}

Firebase AI Logic: La opcion client-side

Si no quieres servidor, Firebase AI Logic es tu mejor opcion. Es ideal para apps que solo necesitan IA en el navegador:

// src/app/ai.service.ts
import { Injectable, inject } from '@angular/core';
import { initializeApp } from 'firebase/app';
import { getVertexAI, getGenerativeModel } from 'firebase/vertexai';

@Injectable({ providedIn: 'root' })
export class AiService {
  private app = initializeApp({ /* tu config */ });
  private vertexAI = getVertexAI(this.app);
  private model = getGenerativeModel(this.vertexAI, { model: 'gemini-2.5-flash' });

  async generateContent(prompt: string): Promise<string> {
    const result = await this.model.generateContent(prompt);
    return result.response.text();
  }
}

"Firebase AI Logic provides a secure way to interact with Vertex AI Gemini API or Imagen API directly from your web and mobile apps" - Source: https://angular.dev/ai


Seguridad: No pongas API keys en el cliente

Esto es critico. Nunca, jamas, pongas tu API key en un archivo que se envie al cliente como environments.ts:

// NUNCA hagas esto
export const environment = {
  apiKey: 'AIzaSy...-', // ESTO ES UNA PESADILLA DE SEGURIDAD
};

Para conexiones del lado del servidor, usa un secrets manager o variables de entorno. Firebase App Hosting ahora proporciona un secrets manager integrado.

"When connecting to model providers, it is important to keep your API secrets safe. Never put your API key in a file that ships to the client" - Source: https://angular.dev/ai


Manejo de respuestas no deterministicas

Los LLMs pueden devolver resultados diferentes para el mismo prompt. Tu aplicacion debe estar preparada:

  1. Ajusta la temperatura para respuestas mas o menos deterministicas.

  2. Human-in-the-loop: deja que un humano verifique respuestas criticas antes de actuar.

  3. Tool calling con schemas: restringe las respuestas del modelo a formatos predefinidos.

  4. Fallbacks: siempre ten un plan B si el modelo no responde o responde mal.


Conclusión

Angular ha dado un paso enorme al integrar IA directamente en su ecosistema. Ya no es necesario buscar soluciones de terceros o inventar la rueda. Con Genkit para full-stack, Firebase AI Logic para client-side, y la Gemini API para control total, tienes todo lo necesario para construir la proxima generacion de aplicaciones web inteligentes.

Para mas contenido sobre Angular y IA, visita Codea Bien.


Referencias adicionales:


SEO

Keywords: Angular IA, Genkit Angular, Gemini API, Firebase AI Logic, aplicaciones inteligentes Angular, tool calling Angular

Meta description: Aprende a construir aplicaciones con IA en Angular usando Genkit, Firebase AI Logic y la Gemini API. Tutorial completo con tool calling y agentic workflows.