TechLead
Lección 4 de 8
5 min de lectura
AI SDK

Hook useCompletion

Crea funciones de completado de texto con useCompletion para autocompletar y generación

El hook useCompletion

El hook useCompletion está diseñado para escenarios de completado de texto de un solo turno, como autocompletar, generación de texto y asistencia de escritura con IA. A diferencia de useChat, no mantiene historial de conversación.

Casos de uso de useCompletion

  • Autocomplete: Sugerencias mientras el usuario escribe
  • Generación de texto: Crear contenido desde un prompt
  • Asistente de escritura: Ayuda a redactar emails, artículos, etc.
  • Completado de código: Sugerencias de código con IA
  • Resúmenes: Resumir texto de entrada

Uso básico

'use client';

import { useCompletion } from 'ai/react';

export default function TextGenerator() {
  const {
    completion,
    input,
    handleInputChange,
    handleSubmit,
    isLoading,
  } = useCompletion();

  return (
    <div className="max-w-xl mx-auto p-4">
      <form onSubmit={handleSubmit}>
        <textarea
          value={input}
          onChange={handleInputChange}
          placeholder="Enter a prompt..."
          className="w-full p-2 border rounded-lg"
          rows={4}
        />
        <button
          type="submit"
          disabled={isLoading}
          className="mt-2 px-4 py-2 bg-purple-500 text-white rounded-lg"
        >
          {isLoading ? 'Generating...' : 'Generate'}
        </button>
      </form>

      {completion && (
        <div className="mt-4 p-4 bg-gray-100 rounded-lg">
          <h3 className="font-semibold mb-2">Result:</h3>
          <p className="whitespace-pre-wrap">{completion}</p>
        </div>
      )}
    </div>
  );
}

Ruta API del servidor

// app/api/completion/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

export async function POST(req: Request) {
  const { prompt } = await req.json();

  const result = streamText({
    model: openai('gpt-4-turbo'),
    prompt,
  });

  return result.toDataStreamResponse();
}

Todas las opciones de useCompletion

const {
  completion,        // The generated text
  input,             // Current input value
  handleInputChange, // Input onChange handler
  handleSubmit,      // Form onSubmit handler
  isLoading,         // Loading state
  error,             // Error state
  stop,              // Stop generation
  setCompletion,     // Manually set completion
  setInput,          // Manually set input
  complete,          // Trigger completion programmatically
} = useCompletion({
  api: '/api/completion',    // API endpoint
  id: 'my-completion',       // Unique ID

  // Callbacks
  onResponse: (response) => {
    console.log('Response started');
  },
  onFinish: (prompt, completion) => {
    console.log('Completed:', completion);
  },
  onError: (error) => {
    console.error('Error:', error);
  },

  // Additional options
  headers: {},
  body: {},
});

Ejemplo de autocomplete

'use client';

import { useCompletion } from 'ai/react';
import { useState, useEffect } from 'react';

export default function Autocomplete() {
  const [debouncedInput, setDebouncedInput] = useState('');
  const { completion, input, setInput, complete, isLoading } = useCompletion({
    api: '/api/autocomplete',
  });

  // Debounce input
  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedInput(input);
    }, 500);
    return () => clearTimeout(timer);
  }, [input]);

  // Trigger completion when debounced input changes
  useEffect(() => {
    if (debouncedInput.length > 10) {
      complete(debouncedInput);
    }
  }, [debouncedInput, complete]);

  const acceptSuggestion = () => {
    setInput(input + completion);
  };

  return (
    <div className="relative">
      <textarea
        value={input}
        onChange={(e) => setInput(e.target.value)}
        className="w-full p-4 border rounded-lg"
        rows={6}
      />

      {completion && !isLoading && (
        <div className="absolute bottom-2 right-2">
          <span className="text-gray-400 italic">{completion}</span>
          <button
            onClick={acceptSuggestion}
            className="ml-2 text-sm text-blue-500"
          >
            Tab to accept
          </button>
        </div>
      )}
    </div>
  );
}

Asistente de escritura

'use client';

import { useCompletion } from 'ai/react';

export default function WritingAssistant() {
  const { completion, complete, isLoading, setCompletion } = useCompletion({
    api: '/api/writing-assist',
  });

  const actions = [
    { label: 'Make it shorter', prompt: 'Make this text more concise:' },
    { label: 'Make it longer', prompt: 'Expand on this text:' },
    { label: 'Fix grammar', prompt: 'Fix grammar and spelling:' },
    { label: 'Make it formal', prompt: 'Rewrite in a formal tone:' },
    { label: 'Make it casual', prompt: 'Rewrite in a casual tone:' },
  ];

  const [text, setText] = useState('');

  const handleAction = (promptPrefix: string) => {
    complete(`${promptPrefix}\n\n${text}`);
  };

  const applyResult = () => {
    setText(completion);
    setCompletion('');
  };

  return (
    <div className="space-y-4">
      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        className="w-full p-4 border rounded-lg"
        rows={6}
        placeholder="Enter your text..."
      />

      <div className="flex flex-wrap gap-2">
        {actions.map((action) => (
          <button
            key={action.label}
            onClick={() => handleAction(action.prompt)}
            disabled={isLoading || !text}
            className="px-3 py-1 bg-gray-100 rounded-full text-sm"
          >
            {action.label}
          </button>
        ))}
      </div>

      {completion && (
        <div className="p-4 bg-purple-50 rounded-lg">
          <p className="whitespace-pre-wrap">{completion}</p>
          <button
            onClick={applyResult}
            className="mt-2 px-4 py-2 bg-purple-500 text-white rounded-lg"
          >
            Apply changes
          </button>
        </div>
      )}
    </div>
  );
}

Completado programático

'use client';

import { useCompletion } from 'ai/react';

export default function ProgrammaticCompletion() {
  const { completion, complete, isLoading } = useCompletion();

  const generateEmailSubject = async () => {
    await complete('Generate a professional email subject line about:' +
      ' requesting a meeting with the marketing team');
  };

  const generateTweet = async () => {
    await complete('Write a tweet about the benefits of TypeScript');
  };

  return (
    <div className="space-y-4">
      <div className="flex gap-2">
        <button onClick={generateEmailSubject}>Email Subject</button>
        <button onClick={generateTweet}>Generate Tweet</button>
      </div>

      {isLoading && <p>Generating...</p>}

      {completion && (
        <div className="p-4 bg-gray-100 rounded-lg">
          {completion}
        </div>
      )}
    </div>
  );
}

useChat vs useCompletion

Característica useChat useCompletion
Historial de mensajesNo
MultiturnoNo
Caso de usoChatbotsCompletados únicos
Salidamessages[]completion string

💡 Puntos clave

  • useCompletion es para generación de texto de un solo turno
  • • Ideal para autocomplete, herramientas de escritura y generaciones únicas
  • • Usa complete() para disparar programáticamente
  • • No mantiene historial conversacional como useChat
  • • Combínalo con debounce para autocomplete en tiempo real

📚 Más recursos

Continuar aprendiendo