Primeiros Passos com a Prompt API — Tutorial Prático
A Prompt API permite enviar prompts em linguagem natural ao Gemini Nano direto no Chrome — sem servidor, sem API key e sem custo por inferência. Este tutorial te leva do zero até o primeiro prompt funcionando: verificação de ambiente, download do modelo, criação de sessão e streaming.
Pré-requisitos
Antes de começar, confere se seu ambiente atende aos requisitos:
| Requisito | Mínimo |
|---|---|
| Chrome | Versão 148+ |
| Sistema operacional | Windows 10/11, macOS 13+, Linux, ChromeOS (Chromebook Plus) |
| Armazenamento livre | 22 GB |
| GPU | >4 GB VRAM (recomendado) |
| CPU (alternativa) | 16 GB RAM + 4 cores |
| Conexão | Sem limite de dados (pro download inicial) |
Passo 1: Verificar a versão do Chrome
Abre o Chrome e vai pra chrome://version. Você precisa da versão 148 ou superior.
Se sua versão é anterior, atualiza:
- Menu (⋮) → Ajuda → Sobre o Google Chrome
- O Chrome busca atualizações automaticamente
- Reinicia o navegador depois da atualização
Passo 2: Verificar o status do modelo
Acesse chrome://on-device-internals no Chrome. Essa página mostra:
- O status atual do Gemini Nano (disponível, baixando, não baixado)
- O tamanho do modelo no disco
- Informações sobre as capacidades disponíveis
Se o modelo ainda não foi baixado, ele desce automaticamente quando uma origem usar a API pela primeira vez. Dá pra forçar o download por essa página de internals também.
Passo 3: Verificar disponibilidade via JavaScript
O primeiro passo no código é sempre checar se a Prompt API tá disponível e se o modelo tá pronto. Use LanguageModel.availability():
async function verificarDisponibilidade() {
// Verifica se a API existe no navegador
if (!('LanguageModel' in window)) {
console.log('Prompt API não suportada neste navegador');
return 'unsupported';
}
// Verifica disponibilidade com as modalidades desejadas
const status = await LanguageModel.availability({
expectedInputs: [{ type: 'text', languages: ['en'] }],
expectedOutputs: [{ type: 'text', languages: ['en'] }]
});
console.log('Status:', status);
return status;
}
const status = await verificarDisponibilidade();
Os valores possíveis de retorno:
| Status | Significado | O que fazer |
|---|---|---|
'available' | Modelo pronto pra uso imediato | Seguir com create() |
'downloading' | Modelo sendo baixado agora | Mostrar progresso ao usuário |
'downloadable' | Modelo pode ser baixado | Chamar create() pra iniciar download |
'unavailable' | Não disponível (hardware insuficiente ou SO não suportado) | Usar fallback |
Detalhe importante: passe as mesmas opções
Sempre passe as mesmas opções pra availability() que você vai usar em prompt() ou promptStreaming(). Isso é crítico porque algumas configurações (como áudio) podem não ser suportadas no hardware do usuário:
// Configuração que será usada em toda a aplicação
const config = {
expectedInputs: [
{ type: 'text', languages: ['en'] },
{ type: 'image' }
],
expectedOutputs: [{ type: 'text', languages: ['en'] }]
};
// Use a mesma config em availability() E em create()
const status = await LanguageModel.availability(config);
const session = await LanguageModel.create(config);
Passo 4: Criar uma sessão com monitor de download
Ao criar uma sessão pela primeira vez, o Chrome pode precisar baixar o modelo. Use o monitor pra acompanhar o progresso:
async function criarSessao() {
const session = await LanguageModel.create({
monitor(m) {
m.addEventListener('downloadprogress', (e) => {
const percentual = Math.round(e.loaded * 100);
console.log(`Download: ${percentual}%`);
// Atualiza a UI pro usuário
document.getElementById('progresso').textContent =
`Baixando modelo de IA: ${percentual}%`;
});
}
});
console.log('Sessão criada!');
return session;
}
Tratando o download pro usuário
O download do Gemini Nano é de ~4,27 GB. Informar o usuário é fundamental — ninguém gosta de espera sem feedback:
async function criarSessaoComUI() {
const statusEl = document.getElementById('status');
const progressEl = document.getElementById('progress-bar');
const status = await LanguageModel.availability({
expectedInputs: [{ type: 'text', languages: ['en'] }],
expectedOutputs: [{ type: 'text', languages: ['en'] }]
});
if (status === 'unavailable') {
statusEl.textContent = 'IA não disponível neste dispositivo';
return null;
}
if (status === 'downloadable' || status === 'downloading') {
statusEl.textContent = 'Preparando modelo de IA...';
progressEl.style.display = 'block';
}
try {
const session = await LanguageModel.create({
monitor(m) {
m.addEventListener('downloadprogress', (e) => {
const pct = Math.round(e.loaded * 100);
progressEl.value = pct;
statusEl.textContent = `Baixando: ${pct}%`;
});
}
});
statusEl.textContent = 'IA pronta!';
progressEl.style.display = 'none';
return session;
} catch (error) {
statusEl.textContent = `Erro: ${error.message}`;
return null;
}
}
Passo 5: Enviar seu primeiro prompt
Com a sessão criada, manda um prompt simples usando session.prompt():
async function primeiroPrompt() {
const session = await LanguageModel.create();
const resposta = await session.prompt('What is the capital of Brazil?');
console.log(resposta);
// "The capital of Brazil is Brasília..."
return resposta;
}
O prompt() retorna uma Promise que resolve com a resposta completa do modelo como string. Simples assim.
Melhorando com system prompt
Pra resultados melhores, use initialPrompts pra definir o comportamento do modelo:
async function promptComContexto() {
const session = await LanguageModel.create({
initialPrompts: [
{
role: 'system',
content: 'You are a concise assistant. Answer in one paragraph maximum.'
}
]
});
const resposta = await session.prompt('Explain what WebAssembly is.');
console.log(resposta);
}
Passo 6: Streaming de respostas
Pra respostas longas ou UX interativa, use promptStreaming() que retorna um ReadableStream:
async function primeiroStreaming() {
const session = await LanguageModel.create();
const stream = session.promptStreaming('Write a short story about a robot.');
const outputEl = document.getElementById('output');
outputEl.textContent = '';
for await (const chunk of stream) {
outputEl.textContent += chunk;
}
}
Streaming com atualização progressiva
async function streamingProgressivo() {
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful coding assistant.' }
]
});
const outputEl = document.getElementById('resposta');
outputEl.textContent = '';
const stream = session.promptStreaming(
'Write a JavaScript function that validates an email address.'
);
for await (const chunk of stream) {
outputEl.textContent += chunk;
}
}
Passo 7: Cancelar um prompt
Use AbortController pra cancelar operações em andamento:
async function promptCancelavel() {
const session = await LanguageModel.create();
const controller = new AbortController();
// Botão de cancelar
document.getElementById('cancelar').onclick = () => {
controller.abort();
console.log('Prompt cancelado pelo usuário');
};
try {
const resposta = await session.prompt(
'Write a very long essay about artificial intelligence.',
{ signal: controller.signal }
);
console.log(resposta);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Operação cancelada');
} else {
throw error;
}
}
}
Exemplo completo: mini aplicação
Aqui vai um exemplo funcional que junta todos os passos:
class PromptAPIApp {
constructor() {
this.session = null;
this.controller = null;
}
async inicializar() {
// 1. Verificar suporte
if (!('LanguageModel' in window)) {
this.mostrarErro('Seu navegador não suporta a Prompt API. Use Chrome 148+.');
return false;
}
// 2. Verificar disponibilidade
const status = await LanguageModel.availability({
expectedInputs: [{ type: 'text', languages: ['en'] }],
expectedOutputs: [{ type: 'text', languages: ['en'] }]
});
if (status === 'unavailable') {
this.mostrarErro('Hardware insuficiente para a Prompt API.');
return false;
}
// 3. Criar sessão
this.session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful, concise assistant.' }
],
monitor(m) {
m.addEventListener('downloadprogress', (e) => {
console.log(`Download: ${Math.round(e.loaded * 100)}%`);
});
}
});
console.log('Prompt API pronta!');
return true;
}
async enviarPrompt(texto) {
if (!this.session) {
throw new Error('Sessão não inicializada');
}
// Cancelar prompt anterior se existir
if (this.controller) {
this.controller.abort();
}
this.controller = new AbortController();
const stream = this.session.promptStreaming(texto, {
signal: this.controller.signal
});
let resposta = '';
for await (const chunk of stream) {
resposta += chunk;
this.atualizarUI(resposta);
}
return resposta;
}
atualizarUI(texto) {
document.getElementById('output').textContent = texto;
}
mostrarErro(msg) {
document.getElementById('erro').textContent = msg;
}
destruir() {
if (this.session) {
this.session.destroy();
this.session = null;
}
}
}
// Uso
const app = new PromptAPIApp();
await app.inicializar();
await app.enviarPrompt('What are the benefits of TypeScript?');
TypeScript: tipagem da API
Pra projetos TypeScript, instale as tipagens oficiais:
npm install @types/dom-chromium-ai
Isso adiciona tipos pra LanguageModel, LanguageModelSession e todos os métodos da API.
Depuração com chrome://on-device-internals
A página chrome://on-device-internals é sua melhor amiga pra diagnóstico:
- Status do modelo: Confirme que o Gemini Nano tá baixado e ativo
- Tamanho: Verifique o espaço ocupado
- Testes: Execute prompts direto pra validar que o modelo funciona
- Logs: Consulte logs de inferência pra troubleshooting
Checklist de verificação
Antes de declarar que tá tudo certo:
- Chrome 148+ instalado
-
chrome://on-device-internalsmostra modelo como disponível -
LanguageModel.availability()retorna'available' -
LanguageModel.create()resolve sem erros -
session.prompt('test')retorna uma resposta - Armazenamento com 22+ GB livres confirmado
Solução de problemas comuns
LanguageModel is undefined
- Verifique se tá usando Chrome 148+
- Confirme que não está em um Web Worker (não é suportado)
- Verifique se está em uma janela top-level ou iframe same-origin
availability() retorna ‘unavailable’
- Hardware não atende os requisitos mínimos (GPU >4GB ou CPU 16GB RAM + 4 cores)
- Espaço livre insuficiente (precisa de 22+ GB)
- SO não suportado (Android/iOS não funcionam)
Download travado
- Verifique sua conexão (precisa ser ilimitada/não medida)
- Tente reiniciar o Chrome
- Consulte
chrome://on-device-internalspro status detalhado
Respostas de baixa qualidade
- O Gemini Nano é um modelo compacto — pra tarefas complexas, considere o polyfill com backend cloud
- Use system prompts claros e específicos
- Fique nos idiomas suportados (EN, ES, JA, DE, FR)
Perguntas frequentes
Preciso de uma API key pra usar a Prompt API?
Não. A Prompt API é completamente gratuita e não requer chave de API, registro ou autenticação. O modelo roda localmente no navegador.
O download do modelo acontece toda vez que o usuário visita meu site?
Não. O modelo é baixado uma única vez pelo Chrome e compartilhado entre todas as origens que usam a Prompt API. Visitas seguintes usam o modelo já em cache.
Posso usar a Prompt API em localhost pra desenvolvimento?
Sim. Funciona em qualquer origem, incluindo localhost e file://, desde que o Chrome e o hardware atendam aos requisitos.
Quanto tempo leva o download do modelo?
Depende da velocidade da conexão. O Gemini Nano tem ~4,27 GB. Numa conexão de 100 Mbps, leva uns 5-7 minutos. Use o monitor pra informar o progresso ao usuário.
A Prompt API funciona com Service Workers?
Não. Não está disponível em Web Workers nem em Service Workers. Funciona apenas em contextos de janela (top-level ou iframes com permissão).