5 demos práticos da Prompt API que você pode copiar
5 demos práticos da Prompt API que você pode copiar
A melhor forma de entender a Prompt API é fazendo ela funcionar. Chega de teoria — aqui é código, output, explicação. Este artigo traz cinco demos completos com os casos de uso que eu considero mais úteis: classificação com JSON Schema, streaming de texto, extração de dados estruturados, chat com contexto e análise de imagens.
TL;DR
- Cinco demos funcionais que você cola no Console do Chrome 148+ e roda na hora
- Classificação com JSON Schema, streaming, extração, chat com memória e gerador de alt text
- Tudo local, sem API key, sem custo — cada demo usa um padrão arquitetural diferente
Cada demo tem código que você copia e cola direto no Console do Chrome 148+. Testei todos antes de publicar — se não rodou no meu Chrome, não entrou aqui.

Antes de começar
Todos os demos precisam de:
- Chrome 148+ com modelo Gemini Nano baixado
- DevTools aberto (
F12) → aba Console - Status
'available'ao rodarawait LanguageModel.availability()
Se precisar de ajuda com setup, veja o tutorial de como testar a Prompt API.
Helper de verificação
Cole isso primeiro para garantir que tudo está pronto:
// Verificação rápida - cole primeiro
async function checkReady() {
if (!('LanguageModel' in window)) {
throw new Error('Prompt API não disponível neste browser');
}
const status = await LanguageModel.availability();
if (status === 'unavailable') {
throw new Error('Hardware não atende requisitos');
}
if (status === 'downloadable' || status === 'downloading') {
console.log(`Status: ${status}. Criando sessão iniciará o download...`);
}
return status;
}
await checkReady();
Demo 1: Classificador de sentimento com JSON Schema
O cenário: classificar reviews, comentários ou feedback automaticamente — com output estruturado garantido, nada de ficar parseando texto livre.
Código completo
// Demo 1: Classificador de Sentimento
const session = await LanguageModel.create({
initialPrompts: [{
role: 'system',
content: 'You are a sentiment classifier. Analyze the sentiment of user messages accurately.'
}]
});
// Schema que força o formato da resposta
const sentimentSchema = {
type: "object",
properties: {
sentiment: {
type: "string",
enum: ["positive", "negative", "neutral", "mixed"]
},
confidence: {
type: "number",
minimum: 0,
maximum: 1
},
reasoning: {
type: "string"
}
},
required: ["sentiment", "confidence", "reasoning"]
};
// Textos de exemplo
const reviews = [
"This product is amazing! Best purchase I've ever made.",
"Terrible service. Waited 3 hours and nobody helped me.",
"It's okay. Nothing special but does the job.",
"Love the design but the battery life is disappointing."
];
console.log('=== Classificador de Sentimento ===\n');
for (const review of reviews) {
const result = await session.prompt(
`Classify the sentiment of this text:\n"${review}"`,
{ responseConstraint: sentimentSchema }
);
const parsed = JSON.parse(result);
console.log(`📝 "${review}"`);
console.log(` → ${parsed.sentiment} (${(parsed.confidence * 100).toFixed(0)}%)`);
console.log(` 💭 ${parsed.reasoning}\n`);
}
session.destroy();
Output esperado
=== Classificador de Sentimento ===
📝 "This product is amazing! Best purchase I've ever made."
→ positive (95%)
💭 Strong positive language with superlatives and enthusiasm
📝 "Terrible service. Waited 3 hours and nobody helped me."
→ negative (92%)
💭 Negative adjective with specific complaint about service failure
📝 "It's okay. Nothing special but does the job."
→ neutral (78%)
💭 Lukewarm language indicating neither satisfaction nor dissatisfaction
📝 "Love the design but the battery life is disappointing."
→ mixed (85%)
💭 Contains both positive sentiment about design and negative about battery
O que está acontecendo
O responseConstraint com enum faz o trabalho pesado aqui. Sem ele, o modelo poderia responder “O sentimento é positivo!” ou qualquer variação criativa. Com o schema, ele é forçado a retornar JSON válido com exatamente um dos valores permitidos.
O minimum/maximum no campo confidence impede que o modelo invente números como 150% ou -3. Parece bobo, mas LLMs fazem coisas assim se você não restringir.
Demo 2: Resumidor de texto com streaming
O cenário: resumir artigos longos mostrando o resultado aparecendo progressivamente. Melhor UX do que esperar 5 segundos olhando para o nada.
Código completo
// Demo 2: Resumidor com Streaming
const session = await LanguageModel.create({
initialPrompts: [{
role: 'system',
content: 'You are a concise summarizer. Create clear, informative summaries in 2-3 sentences.'
}]
});
const longText = `
Artificial intelligence has transformed virtually every industry in the past
decade. From healthcare diagnostics that can detect diseases earlier than human
doctors, to autonomous vehicles navigating complex city streets, AI systems are
becoming increasingly sophisticated. However, this rapid advancement has also
raised significant concerns about job displacement, algorithmic bias, and the
concentration of power among a few large technology companies. Governments
worldwide are now grappling with how to regulate AI development while still
fostering innovation. The European Union's AI Act, passed in 2024, represents
one of the first comprehensive regulatory frameworks, categorizing AI systems
by risk level and imposing strict requirements on high-risk applications.
Meanwhile, the United States has taken a more sector-specific approach, with
different agencies developing their own guidelines for AI use in healthcare,
finance, and transportation.
`;
console.log('=== Resumidor com Streaming ===\n');
console.log('Texto original:', longText.trim().substring(0, 80) + '...\n');
console.log('Resumo (streaming):');
const stream = session.promptStreaming(
`Summarize the following text in exactly 2 sentences:\n\n${longText}`
);
let previousLength = 0;
for await (const chunk of stream) {
const newContent = chunk.substring(previousLength);
process.stdout?.write?.(newContent) || console.log(chunk);
previousLength = chunk.length;
}
console.log('\n\n✅ Resumo completo!');
console.log(`📊 Contexto usado: ${session.contextUsage}/${session.contextWindow} tokens`);
session.destroy();
Output esperado
=== Resumidor com Streaming ===
Texto original: Artificial intelligence has transformed virtually every industry in the past...
Resumo (streaming):
AI has transformed industries from healthcare to transportation while raising concerns
about job displacement and power concentration. Governments are responding with
regulatory frameworks like the EU's AI Act and US sector-specific guidelines to
balance innovation with safety.
✅ Resumo completo!
📊 Contexto usado: 487/4096 tokens
Pegadinha do streaming no Chrome
Lembre-se: no Chrome, o stream é cumulativo. Cada chunk é o texto completo gerado até aquele momento, não o delta. Isso difere da API da OpenAI. Se você está adaptando código que já funcionava com streaming da OpenAI, ajuste a lógica de renderização — senão vai ver o texto inteiro repetido a cada iteração.
Demo 3: Extrator de dados estruturados
O cenário: alguém manda um email bagunçado. Você precisa extrair nomes, emails, datas e valores de forma programática. Regex? Não dá conta. LLM com schema? Funciona.
Código completo
// Demo 3: Extrator de Dados Estruturados
const session = await LanguageModel.create({
initialPrompts: [{
role: 'system',
content: 'You are a data extraction specialist. Extract structured information from unstructured text with high accuracy.'
}]
});
const extractionSchema = {
type: "object",
properties: {
people: {
type: "array",
items: {
type: "object",
properties: {
name: { type: "string" },
role: { type: "string" },
email: { type: "string" }
},
required: ["name"]
}
},
dates: {
type: "array",
items: {
type: "object",
properties: {
date: { type: "string" },
event: { type: "string" }
},
required: ["date", "event"]
}
},
amounts: {
type: "array",
items: {
type: "object",
properties: {
value: { type: "string" },
context: { type: "string" }
},
required: ["value", "context"]
}
}
},
required: ["people", "dates", "amounts"]
};
const unstructuredText = `
Hi team,
Just a reminder that our Q2 review meeting is scheduled for June 15th at 2pm.
Sarah Johnson ([email protected]) will present the financial results showing
$2.4M in revenue, up 15% from last quarter. Mike Chen from engineering will
demo the new feature that cost us $180K to develop. Please confirm attendance
by June 10th.
Thanks,
David Park ([email protected])
VP of Operations
`;
console.log('=== Extrator de Dados Estruturados ===\n');
console.log('Input:', unstructuredText.trim().substring(0, 100) + '...\n');
const result = await session.prompt(
`Extract all people (with roles and emails if mentioned), dates (with associated events), and monetary amounts (with context) from this text:\n\n${unstructuredText}`,
{ responseConstraint: extractionSchema }
);
const data = JSON.parse(result);
console.log('👥 Pessoas encontradas:');
data.people.forEach(p => {
console.log(` • ${p.name}${p.role ? ` (${p.role})` : ''}${p.email ? ` - ${p.email}` : ''}`);
});
console.log('\n📅 Datas encontradas:');
data.dates.forEach(d => {
console.log(` • ${d.date}: ${d.event}`);
});
console.log('\n💰 Valores encontrados:');
data.amounts.forEach(a => {
console.log(` • ${a.value}: ${a.context}`);
});
session.destroy();
Output esperado
=== Extrator de Dados Estruturados ===
Input: Hi team, Just a reminder that our Q2 review meeting is scheduled for June 15th...
👥 Pessoas encontradas:
• Sarah Johnson - [email protected]
• Mike Chen (engineering)
• David Park (VP of Operations) - [email protected]
📅 Datas encontradas:
• June 15th: Q2 review meeting
• June 10th: Deadline to confirm attendance
💰 Valores encontrados:
• $2.4M: Q2 revenue
• $180K: New feature development cost
Por que isso funciona tão bem
A combinação de prompt descritivo + schema com arrays + campos required cria uma “teia” que guia o modelo. Ele sabe exatamente o que precisa encontrar e em que formato retornar. Na minha experiência, para textos curtos e bem escritos (como emails corporativos), a acurácia é surpreendentemente alta — uns 85-90%.
Para textos ambíguos ou mal escritos, cai bastante. Mas aí nenhum modelo se sai bem.
Demo 4: Chat simples com contexto
O cenário: um chatbot que lembra o que você perguntou antes. Parece óbvio, mas a implementação com a Prompt API tem suas particularidades — principalmente o context window limitado.
Código completo
// Demo 4: Chat com Contexto
class SimpleChat {
constructor() {
this.session = null;
this.history = [];
}
async init(systemPrompt) {
this.session = await LanguageModel.create({
initialPrompts: [{
role: 'system',
content: systemPrompt
}]
});
console.log(`💬 Chat iniciado (window: ${this.session.contextWindow} tokens)`);
}
async send(message) {
if (!this.session) throw new Error('Chat não inicializado');
this.history.push({ role: 'user', content: message });
const response = await this.session.prompt(message);
this.history.push({ role: 'assistant', content: response });
const usage = this.session.contextUsage;
const window = this.session.contextWindow;
const percent = ((usage / window) * 100).toFixed(1);
console.log(`\n👤 Você: ${message}`);
console.log(`🤖 Bot: ${response}`);
console.log(` [contexto: ${percent}% usado (${usage}/${window})]`);
return response;
}
async reset() {
if (this.session) this.session.destroy();
this.history = [];
console.log('🔄 Chat resetado');
}
getHistory() {
return this.history;
}
}
// Testando
console.log('=== Chat com Contexto ===\n');
const chat = new SimpleChat();
await chat.init(
'You are a knowledgeable cooking assistant. Give concise, practical answers about recipes and techniques. Keep answers under 3 sentences.'
);
await chat.send('What temperature should I roast chicken at?');
await chat.send('How long for a 2kg bird?');
await chat.send('What herbs go well with it?');
await chat.send('Can you summarize all your suggestions so far?');
// A última resposta mostra que o contexto foi mantido
console.log('\n📋 Histórico salvo:', chat.getHistory().length, 'mensagens');
await chat.reset();
Output esperado
=== Chat com Contexto ===
💬 Chat iniciado (window: 4096 tokens)
👤 Você: What temperature should I roast chicken at?
🤖 Bot: Roast chicken at 200°C (400°F) for crispy skin, or 180°C (350°F) for more even cooking. Higher heat gives better browning.
[contexto: 8.2% usado (336/4096)]
👤 Você: How long for a 2kg bird?
🤖 Bot: For a 2kg chicken at 200°C, roast for about 1 hour and 20 minutes. Use a meat thermometer — the thickest part of the thigh should reach 74°C (165°F).
[contexto: 15.1% usado (618/4096)]
👤 Você: What herbs go well with it?
🤖 Bot: Rosemary, thyme, and sage are classic choices. Stuff the cavity with lemon halves and garlic for extra flavor.
[contexto: 21.4% usado (877/4096)]
👤 Você: Can you summarize all your suggestions so far?
🤖 Bot: Roast your 2kg chicken at 200°C for about 1h20m until the thigh reaches 74°C. Season with rosemary, thyme, and sage, and stuff with lemon and garlic for a flavorful, crispy-skinned result.
[contexto: 30.2% usado (1237/4096)]
📋 Histórico salvo: 8 mensagens
🔄 Chat resetado
Fique de olho no overflow
Com ~4.096 tokens de context window, você tem uns 8-15 turnos antes de estourar. Quando o contexto enche, mensagens antigas são descartadas (exceto o system prompt). Monitore com:
session.addEventListener('contextoverflow', () => {
console.warn('⚠️ Contexto estourou - mensagens antigas descartadas');
});
Na prática, para um FAQ ou assistente rápido, 4K tokens é suficiente. Para conversas longas… vai precisar de cloud.
Demo 5: Gerador de alt text para imagens
O cenário: gerar descrições acessíveis para imagens automaticamente. É um dos use cases que mais me empolgou — acessibilidade quase de graça, rodando 100% no dispositivo do usuário.
Código completo
// Demo 5: Gerador de Alt Text
async function generateAltText(imageSource, context = '') {
const session = await LanguageModel.create({
initialPrompts: [{
role: 'system',
content: 'You are an accessibility expert. Generate concise, descriptive alt text for images. Focus on what is visually important for screen reader users. Keep descriptions under 125 characters when possible.'
}],
expectedInputs: [
{ type: 'text', languages: ['en'] },
{ type: 'image' }
],
expectedOutputs: [{ type: 'text', languages: ['en'] }]
});
const altTextSchema = {
type: "object",
properties: {
altText: {
type: "string",
description: "Concise alt text under 125 characters"
},
longDescription: {
type: "string",
description: "Detailed description for complex images"
},
isDecorative: {
type: "boolean",
description: "Whether image is purely decorative and should have empty alt"
}
},
required: ["altText", "isDecorative"]
};
const contextPrompt = context
? `Context about where this image appears: ${context}\n\n`
: '';
const result = await session.prompt([{
role: 'user',
content: [
{
type: 'text',
value: `${contextPrompt}Generate appropriate alt text for this image. Consider the context and purpose.`
},
{ type: 'image', value: imageSource }
]
}], { responseConstraint: altTextSchema });
session.destroy();
return JSON.parse(result);
}
// Testando com imagem aleatória
console.log('=== Gerador de Alt Text ===\n');
const imageResponse = await fetch('https://picsum.photos/800/600');
const imageBlob = await imageResponse.blob();
const result = await generateAltText(
imageBlob,
'Hero image on a technology blog homepage'
);
console.log('📸 Resultado:');
console.log(` Alt text: "${result.altText}"`);
if (result.longDescription) {
console.log(` Descrição longa: "${result.longDescription}"`);
}
console.log(` Decorativa: ${result.isDecorative ? 'Sim (usar alt="")' : 'Não'}`);
// Bônus: encontrar imagens sem alt na página atual
const pageImages = document.querySelectorAll('img:not([alt]), img[alt=""]');
if (pageImages.length > 0) {
console.log(`\n🔍 ${pageImages.length} imagens sem alt text nesta página`);
const img = pageImages[0];
const imgResult = await generateAltText(img, `Image on ${document.title}`);
console.log(` Imagem: ${img.src.substring(0, 50)}...`);
console.log(` Alt sugerido: "${imgResult.altText}"`);
} else {
console.log('\n✅ Todas as imagens já possuem alt text!');
}
Output esperado
=== Gerador de Alt Text ===
📸 Resultado:
Alt text: "Aerial view of winding mountain road through autumn forest"
Descrição longa: "Drone photograph showing a paved two-lane road curving through dense deciduous forest with orange and yellow fall foliage, mountains visible in the background"
Decorativa: Não
🔍 3 imagens sem alt text nesta página
Imagem: https://example.com/images/hero-banner-202...
Alt sugerido: "Team collaborating around whiteboard with sticky notes"
Integrando num CMS ou editor
Para uso real, você pode conectar a geração de alt text ao input de upload:
document.querySelector('#image-upload').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
// Verificar se Prompt API está disponível
if (!('LanguageModel' in window)) return;
const status = await LanguageModel.availability();
if (status === 'unavailable') return;
const suggestion = await generateAltText(file, 'Blog post image');
if (suggestion) {
document.querySelector('#alt-text-input').value = suggestion.altText;
}
});
É lento (~2-5s com GPU), mas para UX onde o usuário fez upload e está preenchendo outros campos do formulário, funciona como sugestão.
Resumo comparativo
| Demo | Caso de uso | Input | Output | Streaming |
|---|---|---|---|---|
| 1. Sentimento | Classificação | Texto | JSON Schema | Não |
| 2. Resumidor | Geração | Texto longo | Texto livre | Sim |
| 3. Extrator | Extração | Texto não-estruturado | JSON complexo | Não |
| 4. Chat | Conversação | Texto sequencial | Texto livre | Não |
| 5. Alt text | Multimodal | Imagem + texto | JSON Schema | Não |
Conclusão
Esses cinco demos cobrem os padrões que você vai encontrar em 90% dos usos reais da Prompt API:
- Classificação →
responseConstraintcom enum te salva de output maluco - Geração →
promptStreaming()pra não deixar o usuário olhando pro vazio - Extração → JSON Schema com arrays quando regex já não dá conta
- Conversação → session com monitoramento de
contextUsage(e respeito ao limite) - Multimodal →
expectedInputscom image type quando o input não é só texto
Tudo local. Sem API key, sem custo, sem dados vazando do browser. A limitação principal que eu senti: funciona decentemente bem em inglês. Suporte a português? Ainda não é oficial, e na prática a qualidade oscila.
Próximos passos:
- O que é a Prompt API — entenda a API completa
- Prompt API vs. OpenAI — quando usar cada uma
- A controvérsia Google vs. Mozilla — o debate político
FAQ
Os demos funcionam em qualquer site ou só no localhost?
Em qualquer origem — localhost, file://, qualquer domínio HTTPS. A Prompt API está disponível para todas as web pages no Chrome 148+, sem origin trial ou flags.
Posso usar os demos com texto em português?
Parcialmente. O Gemini Nano entende algum português por exposição no treinamento, mas não é oficialmente suportado. Classificação simples pode funcionar; geração e extração terão qualidade inferior.
Quanto de contexto cada demo usa?
Depende do tamanho dos prompts. O Demo 4 (chat) consome mais porque acumula histórico. Os demos 1 e 5 usam pouco porque destroem a sessão após cada uso.
O responseConstraint garante 100% que o JSON será válido?
Na prática, sim — o Chrome valida o output contra o schema antes de retornar. Se o modelo não consegue gerar output válido, o prompt pode falhar com erro. Raro com schemas simples, mas acontece com schemas muito complexos.
Posso usar esses demos em produção?
Sim, com ressalvas: só funciona no Chrome 148+ desktop, precisa de fallback para outros browsers, o modelo pode não estar em todos os dispositivos. Trate como progressive enhancement.