REFERENCIA TÉCNICA
Integración de Firebase AI Logic (Gemini Developer API) en la web de CultivaShop: texto, multimodal (análisis de plantas), streaming, JSON estructurado y seguridad con App Check. Sin backend propio — todo client-side con React + Vite.
Firebase AI Logic Gemini 2.5 Flash React + Vite App Check reCAPTCHA Enterprise Remote Config Streaming SSE
Arquitectura: Client-Side AI (sin backend)
Firebase AI Logic actúa de proxy seguro — no hay servidor intermedio que gestionar
🛒
CultivaShop
React + Vite
🔥
Firebase AI Logic
SDK client-side
Gemini Developer API
Gemini 2.5 Flash
+
🛡️
App Check
reCAPTCHA Enterprise
ℹ️
Sin backend propio: Firebase AI Logic gestiona la autenticación y el rate-limiting. El SDK web llama directamente a Gemini de forma segura mediante App Check, sin exponer API keys al cliente.
1
Setup e Instalación
Pasos de configuración inicial del proyecto CultivaShop
PASO 1
Instalar Firebase
npm install -g firebase@latest
PASO 2
Verificar proyecto
firebase projects:list
PASO 3
Verificar apps
firebase apps:list
PASO 4
Init AI Logic
firebase init ailogic
PASO 5
Habilita Blaze plan
Firebase Console
⚠️
CRÍTICO — Backend Provisioning: Para todos los platforms DEBES ejecutar firebase init ailogic para provisionar el servicio. Solo flutterfire configure NO habilita el servicio de IA y causará errores PERMISSION_DENIED.
src/lib/firebase.js — Inicialización Firebase AI Logic para CultivaShop JavaScript
import { initializeApp } from "firebase/app";
import { getAI, getGenerativeModel, GoogleAIBackend } from "firebase/ai";
import { initializeAppCheck, ReCaptchaEnterpriseProvider } from "firebase/app-check";
import { getRemoteConfig, getValue, fetchAndActivate } from "firebase/remote-config";

// Configuración del proyecto CultivaShop en Firebase
const firebaseConfig = {
  apiKey: "AIzaSy...cultivashop_key",
  authDomain: "cultivashop-prod.firebaseapp.com",
  projectId: "cultivashop-prod",
  storageBucket: "cultivashop-prod.appspot.com",
  messagingSenderId: "847392018456",
  appId: "1:847392018456:web:a3f891bc...",
};

const app = initializeApp(firebaseConfig);

// 🛡️ App Check con reCAPTCHA Enterprise (OBLIGATORIO para producción)
initializeAppCheck(app, {
  provider: new ReCaptchaEnterpriseProvider("6Le...cultivashop_recaptcha_key"),
  isTokenAutoRefreshEnabled: true,
});

// Remote Config: modelo dinámico sin redeploy
const remoteConfig = getRemoteConfig(app);
remoteConfig.defaultConfig = {
  gemini_model: "gemini-2.5-flash",
};
await fetchAndActivate(remoteConfig);
const modelName = getValue(remoteConfig, "gemini_model").asString();

// Inicializar AI Logic con Gemini Developer API
const ai = getAI(app, { backend: new GoogleAIBackend() });

const generationConfig = {
  maxOutputTokens: 2048,
  temperature: 0.7,
  topP: 0.95,
  topK: 40,
};

export const model = getGenerativeModel(ai, {
  model: modelName,  // Desde Remote Config, sin hardcodear
  generationConfig,
});
2
Caso de uso 1 — Asistente de Cultivo (Chat multi-turno)
Responde dudas sobre técnicas, nutrientes y equipamiento con historial de conversación
src/hooks/useCultivaChat.js — Chat con streaming y historial JavaScript
import { useState, useRef } from "react";
import { model } from "../lib/firebase";

const SYSTEM_PROMPT = `Eres el asistente experto de CultivaShop, tienda de cultivo indoor.
Ayudas a cultivadores con:  técnicas hidropónicas, nutrientes, control de plagas,
fases de cultivo, iluminación LED y vertical farming.
Responde siempre en español, de forma amigable y precisa.`;

export function useCultivaChat() {
  const [messages, setMessages] = useState([]);
  const [isStreaming, setIsStreaming] = useState(false);
  const chatRef = useRef(null);

  // Iniciar sesión de chat con system prompt de CultivaShop
  const initChat = () => {
    chatRef.current = model.startChat({
      history: [{
        role: "user",
        parts: [{ text: SYSTEM_PROMPT }],
      }, {
        role: "model",
        parts: [{ text: "¡Hola! Soy el asistente de CultivaShop. ¿En qué te ayudo hoy?" }],
      }],
    });
  };

  // Enviar mensaje con streaming (efecto de escritura en tiempo real)
  const sendMessage = async (userText) => {
    if (!chatRef.current) initChat();
    setIsStreaming(true);

    // Añadir mensaje del usuario al historial UI
    setMessages(prev => [...prev, { role: "user", text: userText }]);

    let aiText = "";
    setMessages(prev => [...prev, { role: "ai", text: "", streaming: true }]);

    // Streaming: cada chunk actualiza la UI en tiempo real
    const result = await chatRef.current.sendMessageStream(userText);
    for await (const chunk of result.stream) {
      aiText += chunk.text();
      setMessages(prev => {
        const updated = [...prev];
        updated[updated.length - 1] = { role: "ai", text: aiText, streaming: true };
        return updated;
      });
    }
    setIsStreaming(false);
  };

  return { messages, isStreaming, sendMessage };
}
cultivashop.es/asistente
Tengo mis tomates cherry en semana 4 de vegetativo. ¿Qué nutrientes necesitan y en qué dosis?
✦ Asistente CultivaShop En semana 4 de vegetativo tus tomates cherry necesitan sobre todo Nitrógeno (N) para el crecimiento foliar. Te recomiendo este esquema:

🌿 N-P-K base: 3-1-2 (alto N, bajo P y K)
💧 EC objetivo: 2.0–2.4 mS/cm | pH: 5.8–6.2
🔬 Micronutrientes: Calcio 150 ppm + Magnesio 50 ppm

En nuestra tienda tienes el Pack Vegetativo Pro de BioBizz que cubre todo esto.
3
Caso de uso 2 — Diagnóstico de Planta por Foto (Multimodal)
El usuario sube una foto, Gemini analiza síntomas y recomienda tratamiento
src/components/PlantDoctor.js — Análisis multimodal de imágenes JavaScript
import { model } from "../lib/firebase";

// Convierte File a parte inlineData para Gemini
async function fileToInlineData(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve({
      inlineData: {
        data: reader.result.split(",")[1],
        mimeType: file.type,  // image/jpeg, image/png...
      }
    });
    reader.readAsDataURL(file);
  });
}

export async function diagnosePlant(imageFile) {
  const imagePart = await fileToInlineData(imageFile);

  const prompt = `Eres un experto en fitosanidad y cultivo indoor.
Analiza esta foto de planta y proporciona:
1. Síntomas observados y probable diagnóstico
2. Causa raíz (deficiencia, plaga, enfermedad, riego...)
3. Tratamiento recomendado con productos específicos
4. Medidas preventivas para evitar recaídas
Responde en español, de forma práctica y concreta.`;

  const result = await model.generateContent([prompt, imagePart]);
  return result.response.text();
}

// Nota: para archivos >20 MB usar Cloud Storage for Firebase en lugar de inline data
4
Caso de uso 3 — Recomendación de Nutrientes (Structured JSON Output)
Gemini devuelve un plan de nutrición estructurado, parseable directamente
src/services/nutrientPlanner.js — JSON schema enforcement JavaScript
import { getGenerativeModel, Schema } from "firebase/ai";
import { ai } from "../lib/firebase";

// Modelo configurado para salida JSON estructurada
const nutrientModel = getGenerativeModel(ai, {
  model: "gemini-2.5-flash",
  generationConfig: {
    responseMimeType: "application/json",
    responseSchema: Schema.object({
      properties: {
        planta:       Schema.string(),
        fase:         Schema.string(),
        semana:       Schema.integer(),
        ec_objetivo: Schema.number(),
        ph_objetivo: Schema.number(),
        npk: Schema.object({
          properties: {
            N: Schema.number(),
            P: Schema.number(),
            K: Schema.number(),
          }
        }),
        productos_recomendados: Schema.array({
          items: Schema.object({
            properties: {
              nombre:   Schema.string(),
              dosis_ml_L: Schema.number(),
              frecuencia: Schema.string(),
            }
          })
        }),
        advertencias: Schema.array({ items: Schema.string() }),
      }
    }),
  }
});

export async function getNutrientPlan({ planta, fase, semana, sistema }) {
  const prompt = `Genera un plan de nutrición para:
- Planta: ${planta} | Fase: ${fase} | Semana: ${semana}
- Sistema: ${sistema} (hidropónico/tierra/coco)
Devuelve exclusivamente el JSON con el esquema especificado.`;

  const result = await nutrientModel.generateContent(prompt);
  return JSON.parse(result.response.text()); // → objeto tipado, sin parse errors
}
API Response — Structured JSON Output
Input: tomates cherry, fase vegetativa, semana 4, sistema hidropónico
{ "planta": "tomate cherry", "fase": "vegetativo", "semana": 4, "ec_objetivo": 2.2, "ph_objetivo": 6.0, "npk": { "N": 180, "P": 60, "K": 120 }, "productos_recomendados": [ { "nombre": "BioBizz Grow", "dosis_ml_L": 4, "frecuencia": "cada riego" }, { "nombre": "Calmag Pro", "dosis_ml_L": 1.5, "frecuencia": "2x semana" }, { "nombre": "Rhizotonic", "dosis_ml_L": 0.5, "frecuencia": "semanal" } ], "advertencias": [ "No mezclar Calmag con fosfatos en el mismo depósito", "Medir EC antes y después de añadir nutrientes" ] }
5
Funcionalidades implementadas en CultivaShop
Resumen de capacidades Firebase AI Logic activas
💬
Chat multi-turno
Asistente con historial de conversación, contexto persistente y system prompt de CultivaShop.
model.startChat()
Streaming SSE
Respuestas en tiempo real con efecto de escritura. UX fluida sin esperar respuesta completa.
generateContentStream()
🔬
Análisis Visual
Diagnóstico de plagas y enfermedades por foto. Multimodal con Base64 inline data.
inlineData + mimeType
📊
JSON Estructurado
Planes de nutrición con Schema tipado. Parse seguro, sin errores de formato.
responseMimeType: json
🛡️
App Check
Protección contra abuso de API. reCAPTCHA Enterprise verifica clientes legítimos.
ReCaptchaEnterpriseProvider
⚙️
Remote Config
Modelo Gemini configurable sin redeploy. Cambia versión desde Firebase Console.
getValue(rc, "gemini_model")
6
Seguridad y Producción
Requisitos obligatorios antes de lanzar CultivaShop a producción
🚨
CRÍTICO — App Check es OBLIGATORIO en producción. Sin él, cualquier cliente puede usar tu cuota de API y acceder a tus recursos de Firebase. Implementar antes del lanzamiento, sin excepción.
🛡️
App Check
reCAPTCHA Enterprise verifica que las peticiones vienen de la app real. Bloquea bots y abuso de quota.
🔑
No exponer API Keys
La firebaseConfig del cliente es pública por diseño, pero App Check impide uso no autorizado.
7
Elección de Proveedor API
Gemini Developer API vs Vertex AI Gemini API para CultivaShop
Característica Gemini Developer API Vertex AI Gemini API Recomendación
Tier gratuito Sí — RPM y tokens gratuitos No (Blaze plan requerido) Dev API para MVP
Plan Firebase requerido Spark (gratuito) para test Blaze (pay-as-you-go) Spark → Dev API
Escalabilidad Limitada por rate limits Enterprise, sin límites Vertex AI a escala
Complejidad setup Baja (1 comando) Media (billing, IAM) Dev API primero
SLA producción Sin garantía 99.9% uptime SLA Vertex AI en prod
Cambio de backend Una línea de código: GoogleAIBackend() → VertexAIBackend() Sin fricción
Estrategia CultivaShop: Arrancar con Gemini Developer API (tier gratuito) para el MVP. Cuando superen 60 rpm o necesiten SLA, migrar a Vertex AI cambiando solo new GoogleAIBackend()new VertexAIBackend() en un fichero. Sin refactoring.
Checklist de lanzamiento
Todos los puntos a verificar antes de poner CultivaShop IA en producción
Pre-producción
Firebase project creado y App registradacultivashop-prod en Firebase Console
firebase init ailogic ejecutadoHabilita Gemini Developer API en el proyecto
Plan Blaze activado para funciones avanzadasRequerido para imagen generation con Nano Banana
App Check configurado con reCAPTCHA EnterpriseCRÍTICO: Implementar antes del launch público
Remote Config con clave gemini_model configuradaValor por defecto: gemini-2.5-flash
Manejo de errores y rate limits implementado429 Too Many Requests, 413 para archivos grandes
Test E2E del flujo completo de asistenteChat, multimodal, JSON output