Saltar al contenido principal

Lo que construirás

Un widget reutilizable que integra el assistant directamente en tu aplicación. El widget ofrece:
  • Un botón flotante que abre un panel de chat al hacer clic
  • Respuestas en tiempo real transmitidas a partir de la información de tu documentación
  • Visualización de mensajes con compatibilidad con Markdown
Los usuarios pueden usar el widget para obtener ayuda con tu producto sin salir de tu aplicación.
Demostración del widget del assistant abriéndose y del usuario escribiendo: How do I get started? Luego el assistant responde.

Requisitos previos

  • Plan Pro o Custom de Mintlify
  • Tu domain, que aparece al final de la URL de tu dashboard. Por ejemplo, si la URL de tu dashboard es https://dashboard.mintlify.com/org-name/domain-name, tu domain es domain-name
  • Una assistant API key
  • Node.js v18 o superior y npm instalado
  • Conocimientos básicos de React

Obtén tu clave de API del assistant

  1. Ve a la página de API keys en tu dashboard.
  2. Haz clic en Create Assistant API Key.
  3. Copia la clave de API del assistant (comienza con mint_dsc_) y guárdala de forma segura.
La clave de API del assistant es un token público que puede usarse en el código del frontend. Las llamadas que usen este token se contabilizan en la cuota de mensajes de tu plan y pueden generar cargos por excedente.

Configurar el ejemplo

La forma más rápida de empezar es clonar el repositorio de ejemplo y personalizarlo según tus necesidades.
1

Clona el repositorio

git clone https://github.com/mintlify/assistant-embed-example.git
cd assistant-embed-example
npm install
2

Configura tu proyecto

Abre src/config.js y actualiza los detalles de tu proyecto de Mintlify:
src/config.js
export const ASSISTANT_CONFIG = {
  domain: 'your-domain',
  docsURL: 'https://yourdocs.mintlify.app',
};
Reemplaza:
  • your-domain por el domain de tu proyecto de Mintlify que encontrarás al final de la URL de tu dashboard.
  • https://yourdocs.mintlify.app por la URL real de tu documentación.
3

Agrega tu token de API

Crea un archivo .env en la raíz del proyecto:
.env
VITE_MINTLIFY_TOKEN=mint_dsc_your_token_here
Reemplaza mint_dsc_your_token_here por tu assistant API key.
4

Inicia el servidor de desarrollo

npm run dev
Abre tu aplicación en un navegador y haz clic en el botón Ask para abrir el widget del assistant.

Estructura del proyecto

El ejemplo usa una arquitectura basada en componentes.
src/
├── App.css                 # Estilos de la aplicación
├── App.jsx                 # Componente principal de la aplicación que renderiza el widget
├── config.js               # Configuración (domain y docsURL)
├── index.css               # Estilos globales
├── main.jsx                # Punto de entrada
├── utils.js                # Funciones auxiliares para analizar sugerencias y extraer sources
└── components/
    ├── AssistantWidget.jsx # Componente principal del widget con estado del chat y lógica de la API
    └── Message.jsx         # Componente de mensaje individual para renderizar mensajes del usuario y del assistant
Archivos clave:
  • src/App.jsx: Componente principal de la app. Muestra cómo importar y usar el componente AssistantWidget.
  • src/config.js: Configuración centralizada. Actualiza este archivo con tu domain y la URL de la documentación.
  • src/components/AssistantWidget.jsx: Componente principal del widget. Gestiona el estado de apertura/cierre, los mensajes del chat y las llamadas a la API.
  • src/utils.js: Contiene funciones utilitarias para analizar el formato de respuesta del assistant y extraer sources.
  • src/components/Message.jsx: Renderiza mensajes individuales con soporte para Markdown y enlaces de sugerencia.

Ideas para personalizar

Citas de fuentes

Extrae y muestra las fuentes de las respuestas del assistant:
const extractSources = (parts) => {
  return parts
    ?.filter(p => p.type === 'tool-invocation' && p.toolInvocation?.toolName === 'search')
    .flatMap(p => p.toolInvocation?.result || [])
    .map(source => ({
      url: source.url || source.path,
      title: source.metadata?.title || source.path,
    })) || [];
};

// In your message rendering:
{messages.map((message) => {
  const sources = message.role === 'assistant' ? extractSources(message.parts) : [];
  return (
    <div key={message.id}>
      {/* contenido del mensaje */}
      {sources.length > 0 && (
        <div className="mt-2 text-xs">
          <p className="font-semibold">Fuentes:</p>
          {sources.map((s, i) => (
            <a key={i} href={s.url} target="_blank" rel="noopener noreferrer" className="text-blue-600">
              {s.title}
            </a>
          ))}
        </div>
      )}
    </div>
  );
})}

Seguimiento de los IDs de los hilos de conversación

Guarda los IDs de los hilos para mantener el historial de la conversación entre sesiones:
import { useState, useEffect } from 'react';

export function AssistantWidget({ domain, docsURL }) {
  const [threadId, setThreadId] = useState(null);

  useEffect(() => {
    // Recuperar el ID del hilo guardado desde localStorage
    const saved = localStorage.getItem('assistant-thread-id');
    if (saved) {
      setThreadId(saved);
    }
  }, []);

  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: `https://api-dsc.mintlify.com/v1/assistant/${domain}/message`,
    headers: {
      'Authorization': `Bearer ${import.meta.env.VITE_MINTLIFY_TOKEN}`,
    },
    body: {
      fp: 'anonymous',
      retrievalPageSize: 5,
      ...(threadId && { threadId }), // Incluir el ID del hilo si está disponible
    },
    streamProtocol: 'data',
    sendExtraMessageFields: true,
    fetch: async (url, options) => {
      const response = await fetch(url, options);
      const newThreadId = response.headers.get('x-thread-id');
      if (newThreadId) {
        setThreadId(newThreadId);
        localStorage.setItem('assistant-thread-id', newThreadId);
      }
      return response;
    },
  });

  // ... resto del componente
}

Añadir atajos de teclado

Permite que los usuarios abran el widget y envíen mensajes mediante atajos de teclado:
useEffect(() => {
  const handleKeyDown = (e) => {
    // Cmd/Ctrl + Shift + I para alternar el widget
    if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'I') {
      e.preventDefault();
      setIsOpen((prev) => !prev);
    }

    // Enter (cuando el widget tiene el foco) para enviar
    if (e.key === 'Enter' && !e.shiftKey && document.activeElement.id === 'assistant-input') {
      e.preventDefault();
      handleSubmit();
    }
  };

  window.addEventListener('keydown', handleKeyDown);
  return () => window.removeEventListener('keydown', handleKeyDown);
}, [handleSubmit]);