Chat Completions · imagem
Envia uma imagem junto da pergunta e recebe a resposta em texto. Mesmo endpoint das chamadas de texto, com o `content` em lista de partes.
Atualizado em 10 de ago. de 2026
O mesmo endereço das chamadas de texto, com uma diferença no corpo: o content da mensagem deixa de ser uma string e passa a ser uma lista de partes, uma delas com a imagem. Rota, autenticação e envelope da resposta são idênticos.
O uso guiado — quanto custa uma imagem, qual modelo escolher, como transformar um documento em campos do seu banco — está em Leitura de imagem. Esta página é o contrato: o que vai no corpo e o que volta.
https://api.hinow.ai/v1/chat/completionsBearerEnvia uma ou mais imagens junto da pergunta e devolve a resposta em texto.
Parâmetros
modelstring· bodyobrigatórioId namespaced do modelo. `hinow/hivision` é o dedicado à leitura de imagem; os modelos de linguagem também aceitam.
messagesarray· bodyobrigatórioMensagens da conversa, como em qualquer chamada. A chamada é sem estado: o contexto é o que você mandar.
messages[].contentstring | array· bodyobrigatórioUma string, quando a mensagem é só texto. Uma **lista de partes**, quando há imagem.
content[].typestring· bodyobrigatório`"text"` ou `"image_url"`, conforme a parte.
content[].textstring· bodyO pedido, na parte `text`.
content[].image_url.urlstring· bodyEndereço público da imagem, ou URL `data:` com o arquivo em base64.
streamboolean· bodyDevolve os tokens conforme saem, por SSE. O `usage` vem no último evento.
temperaturenumber· bodyControla a variação da amostragem. Em extração de campos, valores baixos.
max_tokensinteger· bodyTeto de tokens da resposta. Ao cortar, o `finish_reason` vem `"length"`.
response_formatobject· body`{"type": "json_object"}` solicita conteúdo em JSON. Valide os campos na aplicação.
Respostas
{
"id": "chatcmpl-R2dSu3p8...",
"object": "chat.completion",
"model": "hinow/hivision",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "O gráfico mostra..." },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 389, "completion_tokens": 42, "total_tokens": 431 }
}É a única mudança estrutural em relação a uma chamada de texto. Onde ia uma string, vai uma lista — e a ordem das partes é a ordem em que o modelo as lê. Ponha o pedido antes da imagem quando ele define o que olhar.
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "O que este gráfico mostra? Responda em português, em uma frase."},
{"type": "image_url", "image_url": {"url": "https://exemplo.com/grafico.png"}}
]
}]| Parte | Campo que importa | Para quê |
|---|---|---|
text | text | O pedido, em linguagem natural |
image_url | image_url.url | A imagem, por endereço ou embutida |
O papel continua sendo user
A lista de partes vale para a mensagem do usuário. Instruções gerais — idioma da resposta, formato de saída — continuam melhor em uma mensagem system, em string, como em qualquer chamada de texto.
O campo url aceita as duas coisas, e as duas funcionam:
- Endereço público — a API busca a imagem, então ela precisa estar acessível pela internet. Um endereço em
localhostou atrás de login não serve. - A imagem embutida — uma URL
data:com o arquivo em base64. Não depende de publicar a imagem em lugar nenhum, e é o caminho para o arquivo que o usuário acabou de enviar.
curl https://api.hinow.ai/v1/chat/completions \
-H "Authorization: Bearer $HINOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hinow/hivision",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "O que este gráfico mostra? Responda em português, em uma frase."},
{"type": "image_url", "image_url": {"url": "https://exemplo.com/grafico.png"}}
]
}]
}'import base64, os, requests
with open("grafico.png", "rb") as f:
embutida = "data:image/png;base64," + base64.b64encode(f.read()).decode()
resposta = requests.post(
"https://api.hinow.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['HINOW_API_KEY']}"},
json={
"model": "hinow/hivision",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "O que este gráfico mostra? Responda em português, em uma frase."},
{"type": "image_url", "image_url": {"url": embutida}},
],
}],
},
).json()
print(resposta["choices"][0]["message"]["content"])
print(resposta["usage"]["prompt_tokens"]) # 389 na imagem de testeimport { readFile } from "node:fs/promises";
const bytes = await readFile("grafico.png");
const embutida = `data:image/png;base64,${bytes.toString("base64")}`;
const resposta = await fetch("https://api.hinow.ai/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HINOW_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "hinow/hivision",
messages: [{
role: "user",
content: [
{ type: "text", text: "O que este gráfico mostra? Responda em português, em uma frase." },
{ type: "image_url", image_url: { url: embutida } },
],
}],
}),
}).then((r) => r.json());
console.log(resposta.choices[0].message.content);URL que a API não alcança devolve 502
O erro não diz que o endereço é inválido — diz que a chamada falhou. Se um host público específico falhar enquanto outros funcionam, o problema é alcançabilidade daquele endereço, não falta de suporte a URL. Na dúvida, mande a imagem embutida em base64.
| Formato | Resultado |
|---|---|
| PNG | Funciona |
| JPEG | Funciona |
| WebP | Funciona |
O tipo declarado não é o que decide
Um PNG enviado como data:image/jpeg;base64,... foi lido normalmente — o conteúdo do arquivo é que vale. Ainda assim, declare o tipo certo: é o que mantém o seu próprio código honesto quando o formato mudar.
Mesmo envelope de uma chamada de texto: choices[0].message.content com a resposta, finish_reason com o motivo da parada e usage com o consumo. Não existe campo separado para a imagem — ela já entrou em prompt_tokens.
A contagem tem um comportamento que economiza tempo saber antes: a mesma figura enviada em 512px (19 KB) e em 1024px (55 KB) consumiu 389 tokens de prompt nas duas vezes. Encolher a imagem não barateia a chamada, e pode custar a legibilidade de um texto pequeno — envie em uma resolução em que uma pessoa conseguiria ler.
Acrescente outra parte image_url na mesma lista. Serve para comparar duas versões de um documento, conferir antes e depois, ou pedir uma conclusão sobre um conjunto.
"content": [
{"type": "text", "text": "Estes dois documentos são da mesma empresa? Responda sim ou não e por quê."},
{"type": "image_url", "image_url": {"url": "https://exemplo.com/nota-a.png"}},
{"type": "image_url", "image_url": {"url": "https://exemplo.com/nota-b.png"}}
]Cada imagem soma à conta: com duas de 1024px, o prompt foi a 660 tokens — contra 389 de uma só.
Com stream: true a resposta chega por server-sent events, exatamente como em uma chamada de texto: os pedaços vêm em choices[0].delta.content, o usage só aparece no último evento e o fluxo encerra com data: [DONE].
A imagem não muda nada aqui — ela é consumida por inteiro na entrada, antes do primeiro token sair. O que muda é a espera até esse primeiro token, que é maior do que em uma chamada só de texto.
| Situação | Código | O que fazer |
|---|---|---|
| A API não alcança o endereço da imagem | 502 | Mande a imagem embutida em base64 |
content em string, com imagem esperada | 400 | Troque por lista de partes |
Modelo que não atende Chat Completions, como hinow/hiembed | 400 | Confira a modalidade em GET https://api.hinow.ai/v1/models |
| Modelo inexistente ou não liberado | 404 | Confira o id namespaced |
| Limite por minuto estourado | 429 | Repita com espera progressiva |
| Chamada sem imagem nenhuma | 200 | Responde normalmente, mas o usage volta zerado |
Confirme o contrato da sua conta
Disponibilidade, preços e modalidades evoluem. GET https://api.hinow.ai/v1/models devolve o catálogo vigente — mas trate o campo category como informativo: modelos listados só como text_to_text aceitaram imagem nos testes.

