Criar API Detector de Imagens IA com C2PA e Classificador

Ashley Innocent

Ashley Innocent

21 maio 2026

Criar API Detector de Imagens IA com C2PA e Classificador

Apidog para empresas

Implantação local

SSO & RBAC

Conforme SOC 2

Explorar Apidog Enterprise

Alguém envia uma foto para o seu produto e afirma que uma câmera a tirou. Seu backend pode provar ou refutar isso? Os geradores de imagem agora produzem resultados que parecem reais para um revisor humano, então “confiar nos olhos” deixou de funcionar há um tempo. A boa notícia é que você não precisa treinar seu próprio modelo para entregar uma resposta útil. Você pode combinar dois sinais independentes, um manifesto de proveniência criptográfica e um classificador de aprendizado de máquina, em um único veredito que é mais honesto do que qualquer um dos sinais isoladamente.

Este tutorial aborda a construção desse backend como um único serviço com um endpoint POST /verify. Você o alimenta com uma imagem, e ele retorna um veredito JSON com uma pontuação de confiança e os detalhes de proveniência encontrados. Usaremos Python e FastAPI para o servidor, as ferramentas C2PA de código aberto para o sinal de proveniência e uma API de detecção hospedada para o sinal do classificador. Como este é um projeto de API, também projetaremos o contrato do endpoint primeiro e usaremos o Apidog para simular e testá-lo, para que sua equipe de frontend possa começar a integrar antes que o código do backend seja finalizado.

TL;DR

Você construirá um serviço FastAPI expondo POST /verify que aceita um upload de imagem, extrai e valida seu manifesto C2PA Content Credentials com a biblioteca c2pa-python, chama um classificador de detecção de IA hospedado como um segundo sinal independente, e retorna um único veredito JSON (provavelmente_autêntico, provavelmente_ia ou incerto) com uma pontuação de confiança e os detalhes brutos de proveniência. Você também projetará o esquema OpenAPI para o endpoint e usará o Apidog para gerar um servidor mock e executar testes de endpoint contra ele.

button

Por que dois sinais em vez de um

Antes de qualquer código, ajuda ter clareza sobre o que você está detectando. Não há uma única propriedade de um arquivo que diga “um humano fez isso” ou “uma IA fez isso”. Em vez disso, há pistas, e cada pista detecta um tipo diferente de imagem, enquanto ignora outras.

A primeira pista é a proveniência. C2PA, a Coalition for Content Provenance and Authenticity, é um padrão aberto que anexa metadados à prova de adulteração e criptograficamente assinados a um arquivo de mídia. Esse pacote de metadados é chamado de manifesto, e o nome para o usuário é Content Credentials. Quando uma ferramenta participante, uma câmera, um editor ou um gerador de imagem, cria ou altera uma imagem, ela pode escrever um manifesto que registra o que aconteceu e o assina com um certificado. Se você puder ler e validar esse manifesto, obterá uma declaração forte e verificável sobre o histórico da imagem.

O problema: C2PA é opt-in, e o manifesto é frágil. Uma captura de tela o remove. A recodificação através de um aplicativo de mensagens o remove. Muitas plataformas removem metadados no upload. Portanto, um manifesto ausente não lhe diz quase nada; não significa que a imagem é falsa, e não significa que é real.

A segunda pista é um classificador estatístico. Um modelo de detecção é treinado em milhões de imagens reais e geradas e aprende os artefatos visuais que os geradores tendem a deixar para trás. Ele funciona em qualquer imagem, com ou sem metadados, mas é probabilístico. Retorna uma probabilidade, não um fato, e pode estar errado, especialmente em imagens fora de sua distribuição de treinamento ou imagens que foram fortemente comprimidas.

Nenhum sinal é suficiente por si só. A proveniência é precisa, mas raramente presente. O classificador está sempre disponível, mas nunca é certo. Combine-os e você obterá um veredito que diz, em efeito, “aqui está o que a criptografia prova, aqui está o que o modelo estima, e aqui está o quão confiante a combinação nos torna”. Esse é o objetivo do design. Se você deseja uma análise mais aprofundada do porquê as abordagens de sinal único falham, nosso artigo sobre por que a detecção de imagem de IA falha cobre os modos de falha em detalhes.

Visão geral da arquitetura

O serviço é pequeno de propósito. Um endpoint, duas chamadas downstream, uma resposta combinada.

                ┌─────────────────────────────┐
   image  ──▶   │   FastAPI  POST /verify      │
                │                              │
                │   1. validate upload         │
                │   2. ┌──────────────────┐    │
                │      │ C2PA manifest     │    │  provenance signal
                │      │ (c2pa-python)     │    │
                │      └──────────────────┘    │
                │   3. ┌──────────────────┐    │
                │      │ classifier API    │    │  statistical signal
                │      │ (hosted detector) │    │
                │      └──────────────────┘    │
                │   4. combine into verdict    │
                └─────────────────────────────┘
                              │
                              ▼
                   JSON verdict + confidence

O Passo 1 verifica se o upload é uma imagem real de um tipo suportado e dentro de um limite de tamanho. O Passo 2 lê o manifesto C2PA localmente; sem chamada de rede, apenas análise e validação de certificado. O Passo 3 envia os bytes da imagem para um classificador hospedado via HTTPS. O Passo 4 mescla os dois resultados com uma pequena função de regras e retorna o veredito.

As duas etapas de sinal são independentes. Isso é importante para o tratamento de erros: se o classificador expirar, você ainda pode retornar um veredito parcial do sinal de proveniência, e vice-versa. Retornaremos a isso na seção de reforço.

Para a stack, Python 3.10 ou mais recente é necessário porque a biblioteca C2PA precisa dele. Você usará FastAPI para a camada web, Uvicorn para executá-lo, python-multipart para uploads de arquivos, httpx para a chamada do classificador externo e c2pa-python para a proveniência.

pip install fastapi "uvicorn[standard]" python-multipart httpx c2pa-python

O sinal C2PA

A Content Authenticity Initiative, sob a organização `contentauth` do GitHub, publica as ferramentas C2PA de código aberto. Há duas partes sobre as quais você ouvirá falar:

O caminho de leitura da biblioteca se concentra em um objeto `Reader`. Você o aponta para uma imagem e, em seguida, solicita o armazenamento do manifesto como JSON. Aqui está o núcleo do módulo de proveniência.

# provenance.py
import json
import c2pa


def read_provenance(image_path: str) -> dict:
    """
    Read and validate the C2PA manifest from an image.
    Returns a normalized dict describing what was found.
    """
    try:
        with c2pa.Reader(image_path) as reader:
            manifest_store = json.loads(reader.json())
    except c2pa.C2paError as err:
        # ManifestNotFound is the expected case for most images.
        if str(err).startswith("ManifestNotFound"):
            return {
                "has_manifest": False,
                "validation": "none",
                "detail": "No C2PA manifest present in this image.",
            }
        # Any other C2paError means the file had C2PA data we could not parse.
        return {
            "has_manifest": True,
            "validation": "error",
            "detail": f"Could not parse manifest: {err}",
        }

    active_label = manifest_store.get("active_manifest")
    manifests = manifest_store.get("manifests", {})
    active = manifests.get(active_label, {})

    # validation_status appears only when there are validation problems.
    validation_status = manifest_store.get("validation_status", [])
    validation = "valid" if not validation_status else "invalid"

    claim_generator = active.get("claim_generator", "unknown")
    signature_issuer = active.get("signature_info", {}).get("issuer", "unknown")

    return {
        "has_manifest": True,
        "validation": validation,
        "claim_generator": claim_generator,
        "signature_issuer": signature_issuer,
        "validation_status": validation_status,
        "detail": "Manifest read successfully.",
    }

Algumas notas sobre o que o código faz. O `Reader` é usado como um gerenciador de contexto para que os recursos subjacentes sejam liberados. `reader.json()` retorna o armazenamento completo do manifesto como uma string JSON; a biblioteca também oferece `reader.detailed_json()` se você quiser o relatório detalhado com cada asserção e ingrediente. O resultado esperado para a maioria dos uploads é um `C2paError` cuja mensagem começa com `ManifestNotFound`, porque a maioria das imagens simplesmente não possui Content Credentials. Trate isso como dado, não como uma falha.

Quando um manifesto está presente, dois campos são os mais importantes para um veredito. A string `claim_generator` informa qual ferramenta escreveu o manifesto, por exemplo, uma string de firmware de câmera ou o nome de uma ferramenta de imagem de IA. O array `validation_status` está vazio quando a assinatura e os hashes são verificados, e é preenchido com códigos de erro quando não são. Um manifesto inválido é um sinal de alerta que merece ser exposto; significa que o arquivo alega um histórico que a criptografia não suporta.

O que este sinal não pode fazer: ele não pode lhe dar um veredito quando não há manifesto, o que ocorre na maioria das vezes. É exatamente por isso que você precisa do segundo sinal.

O sinal do classificador

O classificador é uma API hospedada que pontua a probabilidade de uma imagem ser gerada por IA. Vários fornecedores oferecem isso. Este tutorial usa o Sightengine porque seu modelo de detecção de IA tem uma API HTTP documentada e um formato de resposta claro, mas o padrão é o mesmo para qualquer provedor; você troca a URL, os parâmetros e o campo que você lê. Se você está avaliando opções, nosso resumo das melhores APIs de detecção de imagem de IA compara precisão, preços e cobertura entre os fornecedores.

O endpoint de verificação do Sightengine é `https://api.sightengine.com/1.0/check.json`. Você faz um POST da imagem como `media`, define `models` como `genai` e passa seu `api_user` e `api_secret`. A resposta inclui `type.ai_generated`, uma pontuação de 0 a 1 onde um valor mais alto significa mais provável de ser gerado por IA.

# classifier.py
import httpx

SIGHTENGINE_URL = "https://api.sightengine.com/1.0/check.json"


async def classify_image(
    image_bytes: bytes,
    filename: str,
    api_user: str,
    api_secret: str,
    timeout_seconds: float = 8.0,
) -> dict:
    """
    Send the image to the hosted detector.
    Returns a normalized dict with the AI-generated score.
    """
    data = {
        "models": "genai",
        "api_user": api_user,
        "api_secret": api_secret,
    }
    files = {"media": (filename, image_bytes)}

    try:
        async with httpx.AsyncClient(timeout=timeout_seconds) as client:
            response = await client.post(SIGHTENGINE_URL, data=data, files=files)
            response.raise_for_status()
            payload = response.json()
    except httpx.TimeoutException:
        return {"available": False, "reason": "classifier_timeout"}
    except httpx.HTTPStatusError as err:
        return {
            "available": False,
            "reason": f"classifier_http_{err.response.status_code}",
        }
    except httpx.HTTPError as err:
        return {"available": False, "reason": f"classifier_error: {err}"}

    if payload.get("status") != "success":
        return {
            "available": False,
            "reason": payload.get("error", {}).get("message", "unknown_error"),
        }

    ai_score = payload.get("type", {}).get("ai_generated")
    if ai_score is None:
        return {"available": False, "reason": "missing_score_in_response"}

    return {"available": True, "ai_score": float(ai_score)}

A função é assíncrona para que um classificador lento não bloqueie o loop de eventos. O tempo limite é explícito e curto; oito segundos é um padrão sensato para um endpoint interativo, e você deve ajustá-lo à latência real do seu provedor. Cada caminho de falha retorna `available: False` com um motivo legível por máquina em vez de levantar uma exceção. Isso é deliberado: uma interrupção do classificador deve degradar o veredito, não travar a requisição. A lógica do veredito na próxima seção lê `available` e decide o que fazer.

Trate a pontuação como uma estimativa. Um 0,92 significa “o modelo está razoavelmente seguro”, não “isso é IA comprovada”. Os fornecedores atualizam seus modelos, e a precisão varia por gerador e pela quantidade de compressão que a imagem sofreu antes de chegar a você. Para uma visão mais ampla de como essas ferramentas se comportam na prática, consulte nosso guia sobre como verificar se uma imagem é gerada por IA.

Projetando o contrato /verify

Aqui é a parte onde o Apidog ganha seu lugar. Antes de escrever o manipulador de rota, projete a requisição e a resposta como um esquema OpenAPI. Fazer isso primeiro lhe dá três coisas: uma única fonte de verdade na qual ambas as equipes concordam, um servidor mock que o frontend pode chamar imediatamente, e um conjunto de testes que você pode executar no momento em que o backend existir.

A requisição

POST /verify recebe um corpo `multipart/form-data` com um campo, `image`, o arquivo a ser verificado. Mantenha-o simples assim. Parâmetros de consulta opcionais podem vir depois.

A resposta

A resposta é onde o trabalho de design compensa. Ela deve mostrar o veredito final, a confiança e ambos os sinais brutos para que um chamador possa auditar a decisão. Aqui está o formato.

{
  "verdict": "likely_ai",
  "confidence": 0.86,
  "signals": {
    "provenance": {
      "has_manifest": true,
      "validation": "valid",
      "claim_generator": "SomeImageTool/2.1",
      "signature_issuer": "Some Issuing CA"
    },
    "classifier": {
      "available": true,
      "ai_score": 0.91
    }
  },
  "explanation": "Um manifesto C2PA válido nomeia uma ferramenta de imagem de IA, e o classificador pontuou a imagem como provavelmente gerada por IA.",
  "checked_at": "2026-05-21T09:30:00Z"
}

verdict é um de três valores de string: provavelmente_autêntico, provavelmente_ia ou incerto. Três valores, não dois, porque a honestidade importa; quando os sinais discordam ou são ambos fracos, “incerto” é a resposta correta. `confidence` é um float de 0 a 1 descrevendo quão fortemente os sinais suportam esse veredito. `signals` carrega ambas as entradas brutas para que o chamador possa mostrar sua própria UI ou aplicar sua própria política. `explanation` é uma frase legível por humanos para a equipe de suporte e logs.

Expressar isso como um esquema OpenAPI é direto. Aqui está o componente de resposta que você colocaria em sua especificação.

components:
  schemas:
    VerifyResponse:
      type: object
      required: [verdict, confidence, signals, checked_at]
      properties:
        verdict:
          type: string
          enum: [provavelmente_autêntico, provavelmente_ia, incerto]
        confidence:
          type: number
          format: float
          minimum: 0
          maximum: 1
        signals:
          type: object
          properties:
            provenance:
              type: object
              properties:
                has_manifest: { type: boolean }
                validation:
                  type: string
                  enum: [valid, invalid, error, none]
                claim_generator: { type: string }
                signature_issuer: { type: string }
            classifier:
              type: object
              properties:
                available: { type: boolean }
                ai_score:
                  type: number
                  format: float
        explanation: { type: string }
        checked_at: { type: string, format: date-time }

Você pode criar este esquema diretamente no designer visual do Apidog ou importar um arquivo OpenAPI existente. Projetar a API antes da implementação é um fluxo de trabalho que vale a pena adotar em geral; nosso passo a passo do modo spec-first mostra como fazer isso de ponta a ponta no Apidog.

Visita guiada pelo código

Agora as peças se encaixam. Abaixo está o aplicativo FastAPI: validação de entrada, ambas as chamadas de sinal, a função de combinação e a rota.

Combinando os dois sinais

A função de veredito é o coração do serviço. Ela codifica sua política. A proveniência, quando válida e presente, é o sinal mais forte porque é criptográfica; o classificador é um desempate e um fallback. Aqui está uma versão clara e conservadora.

# verdict.py


def combine_signals(provenance: dict, classifier: dict) -> dict:
    """Merge the provenance and classifier signals into one verdict."""
    has_manifest = provenance.get("has_manifest", False)
    validation = provenance.get("validation", "none")
    generator = (provenance.get("claim_generator") or "").lower()

    classifier_ok = classifier.get("available", False)
    ai_score = classifier.get("ai_score")

    # Heurística: ferramentas de IA conhecidas tendem a se identificar no manifesto.
    ai_keywords = ("firefly", "dall-e", "dalle", "midjourney", "stable",
                   "gpt", "gemini", "imagen", "generat")
    generator_looks_ai = any(k in generator for k in ai_keywords)

    # Caso 1: um manifesto válido que nomeia um gerador de IA. Sinal forte de IA.
    if has_manifest and validation == "valid" and generator_looks_ai:
        return _verdict("provavelmente_ia", 0.95,
                        "Um manifesto C2PA válido nomeia uma ferramenta de imagem de IA.")

    # Caso 2: um manifesto válido de uma câmera ou editor não-IA. Sinal autêntico forte.
    if has_manifest and validation == "valid" and not generator_looks_ai:
        if classifier_ok and ai_score is not None and ai_score > 0.85:
            return _verdict("incerto", 0.55,
                            "O manifesto parece autêntico, mas o classificador "
                            "discorda; os sinais entram em conflito.")
        return _verdict("provavelmente_autêntico", 0.9,
                        "Um manifesto C2PA válido de uma ferramenta não-IA está presente.")

    # Caso 3: um manifesto que falha na validação. Trate como suspeito.
    if has_manifest and validation in ("invalid", "error"):
        return _verdict("incerto", 0.6,
                        "A imagem possui um manifesto C2PA que falhou na "
                        "validação; seu histórico declarado não é verificado.")

    # Caso 4: sem manifesto. Recorra inteiramente ao classificador.
    if classifier_ok and ai_score is not None:
        if ai_score >= 0.7:
            return _verdict("provavelmente_ia", round(ai_score, 2),
                            "Sem dados de proveniência; o classificador pontuou a "
                            "imagem como provavelmente gerada por IA.")
        if ai_score <= 0.3:
            return _verdict("provavelmente_autêntico", round(1 - ai_score, 2),
                            "Sem dados de proveniência; o classificador pontuou a "
                            "imagem como provavelmente autêntica.")
        return _verdict("incerto", 0.5,
                        "Sem dados de proveniência e a pontuação do classificador é "
                        "inconclusiva.")

    # Caso 5: sem manifesto e sem classificador. Não podemos realmente dizer.
    return _verdict("incerto", 0.0,
                    "Sem dados de proveniência e o classificador estava indisponível.")


def _verdict(verdict: str, confidence: float, explanation: str) -> dict:
    return {"verdict": verdict, "confidence": confidence,
            "explanation": explanation}

Leia os cinco casos e você poderá ver a política. Um manifesto válido domina. Um manifesto falho é um aviso, não uma prova de falsidade, então ele cai em “incerto”. Um conflito entre um manifesto limpo e uma alta pontuação do classificador também cai em “incerto” em vez de escolher um lado. E quando ambos os sinais estão ausentes, o serviço o declara honestamente com confiança zero, em vez de adivinhar. Você ajustará esses limites para sua própria tolerância a riscos; uma plataforma de conteúdo e uma redação traçariam as linhas de forma diferente.

O aplicativo FastAPI

# main.py
import os
import tempfile
from datetime import datetime, timezone

from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.responses import JSONResponse

from provenance import read_provenance
from classifier import classify_image
from verdict import combine_signals

app = FastAPI(title="API de Detecção de Imagens de IA", version="1.0.0")

ALLOWED_TYPES = {"image/jpeg", "image/png", "image/webp"}
MAX_BYTES = 12 * 1024 * 1024  # 12 MB

SIGHTENGINE_USER = os.environ.get("SIGHTENGINE_API_USER", "")
SIGHTENGINE_SECRET = os.environ.get("SIGHTENGINE_API_SECRET", "")


@app.post("/verify")
async def verify(image: UploadFile = File(...)):
    # 1. Validar o upload.
    if image.content_type not in ALLOWED_TYPES:
        raise HTTPException(
            status_code=415,
            detail=f"Tipo não suportado {image.content_type}. "
                   f"Envie JPEG, PNG ou WebP.",
        )

    image_bytes = await image.read()
    if len(image_bytes) == 0:
        raise HTTPException(status_code=400, detail="Arquivo vazio.")
    if len(image_bytes) > MAX_BYTES:
        raise HTTPException(status_code=413, detail="O arquivo excede o limite de 12 MB.")

    # 2. Sinal de proveniência. O leitor C2PA precisa de um caminho de arquivo,
    #    então escrevemos em um arquivo temporário e o limpamos depois.
    suffix = os.path.splitext(image.filename or "")[1] or ".img"
    with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
        tmp.write(image_bytes)
        tmp_path = tmp.name
    try:
        provenance = read_provenance(tmp_path)
    finally:
        os.unlink(tmp_path)

    # 3. Sinal do classificador. Falhas retornam available: False, não exceções.
    if SIGHTENGINE_USER and SIGHTENGINE_SECRET:
        classifier = await classify_image(
            image_bytes, image.filename or "upload",
            SIGHTENGINE_USER, SIGHTENGINE_SECRET,
        )
    else:
        classifier = {"available": False, "reason": "classifier_not_configured"}

    # 4. Combinar e responder.
    result = combine_signals(provenance, classifier)
    return JSONResponse({
        "verdict": result["verdict"],
        "confidence": result["confidence"],
        "signals": {
            "provenance": {
                k: provenance.get(k) for k in
                ("has_manifest", "validation", "claim_generator",
                 "signature_issuer")
            },
            "classifier": {
                "available": classifier.get("available", False),
                "ai_score": classifier.get("ai_score"),
            },
        },
        "explanation": result["explanation"],
        "checked_at": datetime.now(timezone.utc).isoformat(),
    })

Execute-o localmente com `uvicorn main:app --reload` e o endpoint estará ativo em `http://127.0.0.1:8000/verify`. O leitor C2PA espera um caminho de arquivo, então o manipulador escreve o upload em um arquivo temporário e o exclui em um bloco `finally`; o classificador funciona diretamente com os bytes. Observe que a requisição nunca falha devido a um manifesto ausente ou um classificador indisponível; ambos são estados normais que a função de veredito trata.

Um backend projetado dessa forma, um serviço focado com um contrato limpo, se encaixa na tendência mais ampla de produtos que expõem sua capacidade central através de uma API. Se essa ideia lhe interessa, nosso ensaio sobre software headless vale a leitura.

Testando e simulando com Apidog

Aqui está o problema do fluxo de trabalho: sua equipe de frontend quer construir a UI de upload e o painel de resultados agora, mas o backend acima leva alguns dias para ser finalizado, obter chaves e ser implantado. Você não quer que eles sejam bloqueados. É para isso que servem os servidores mock, e é onde projetar o esquema primeiro compensa.

Gerar um servidor mock a partir do esquema

Importe o esquema OpenAPI para o Apidog, ou construa o endpoint `/verify` no designer visual. O Apidog lê o esquema de resposta e gera um servidor mock automaticamente. Como o esquema define tipos de campo e enums, o mock retorna dados formatados exatamente como o endpoint real: um `verdict` que é um dos três valores de enum, um float `confidence` entre 0 e 1, um objeto `signals` preenchido. O frontend aponta sua chamada `fetch` para a URL mock do Apidog e obtém respostas realistas no primeiro dia. Quando o backend real for lançado, eles mudam uma única URL base.

O mock também é onde você pratica os casos difíceis antes que qualquer código real exista. Defina respostas de exemplo para os vereditos que importam:

O frontend pode construir e estilizar cada estado, incluindo os estados de erro, contra o mock. É assim que você lança uma UI e uma API em paralelo, em vez de em sequência.

Executar testes de endpoint no Apidog

Assim que o backend estiver em execução, crie uma requisição no Apidog para `POST /verify`. Defina o método, aponte-o para sua URL local e, na aba Body, escolha `form-data`, adicione o campo `image`, defina seu tipo como File e escolha uma imagem de teste do disco.

Envie, e o Apidog mostrará a resposta JSON. Agora adicione asserções para que isso se torne uma verificação repetível em vez de um clique único:

Construa um pequeno cenário de teste que execute vários uploads em sequência: uma imagem com Content Credentials, um JPEG simples sem manifesto, um arquivo muito grande e um arquivo não-imagem renomeado com a extensão `.jpg`. Cada um verifica um ramo diferente da sua lógica de veredito e da sua validação de entrada. Salve o cenário e você poderá reexecutar todo o conjunto após cada alteração, ou conectá-lo ao CI para que uma regressão na função de veredito falhe na construção. Testar um endpoint de upload manualmente com `curl` fica chato rapidamente; um cenário salvo não.

Reforço e casos limite

O caminho feliz são os fáceis 80 por cento. Um serviço de verificação vive ou morre nos outros 20 por cento, porque as entradas são, por natureza, adversariais; alguém está tentando fazer passar uma imagem por algo que não é.

O que cada sinal detecta e perde

Esta tabela é o modelo mental a ser mantido. É por isso que o serviço usa ambos.

Cenário Sinal de proveniência C2PA Sinal do classificador
Imagem de IA de uma ferramenta que escreve Content Credentials Detecta: manifesto nomeia o gerador Geralmente detecta: artefatos presentes
Imagem de IA com metadados removidos (captura de tela, re-upload) Perde: nenhum manifesto para ler Detecta: funciona em pixels, sem necessidade de metadados
Foto real de uma câmera que assina Content Credentials Confirma: manifesto válido, gerador não-IA Pode ser falso-positivo em compressão pesada ou edições
Foto real sem metadados Sem sinal: nada para validar Melhor palpite apenas: probabilístico, pode estar errado
Imagem com manifesto forjado ou adulterado Detecta: validation_status sinaliza a falha Pode ou não detectar, depende dos pixels
Gerador novo no qual o classificador não foi treinado Detecta apenas se a ferramenta escreve um manifesto Frequentemente perde: fora da distribuição de treinamento
Foto real fortemente editada (retoque de IA em base real) Manifesto, se presente, registra o histórico de edição Ambíguo: parcialmente sintético, pontuação fica no meio do intervalo

Leia cada linha e você verá a mesma história: onde um sinal é cego, o outro frequentemente não é. A proveniência é exata, mas esparsa; o classificador é universal, mas difuso. O veredito combinado é mais confiável do que qualquer coluna sozinha, e o valor honesto `incerto` existe para as linhas onde ambos os sinais são fracos.

Casos de uso no mundo real

Este padrão não é acadêmico. Alguns lugares onde ele se encaixa diretamente:

O fio condutor comum: você quer uma primeira passagem rápida e automatizada que seja honesta sobre sua própria incerteza, para que a atenção humana vá para onde é realmente necessária.

Conclusão

Detectar imagens geradas por IA de forma eficaz não se trata de encontrar um teste perfeito. Trata-se de combinar sinais independentes e ser honesto sobre a confiança.

Para construir isso de verdade, projete o esquema `/verify`, gere um servidor mock e execute seus testes de endpoint em um só lugar. Baixe o Apidog para projetar, simular e testar a API enquanto a constrói, então passe do mock para o backend ativo com uma única mudança de URL base.

button

Pratique o design de API no Apidog

Descubra uma forma mais fácil de construir e usar APIs