File size: 4,122 Bytes
1352e55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python
"""AIDA P0 — CLI de inferência.



    python predict.py imagem.jpg

    python predict.py imagem.jpg --json

    python predict.py *.jpg --json           # uma linha JSON por imagem

    python predict.py imagem.jpg --models-dir /outro/models



Códigos de saída:



    0  todas as imagens foram analisadas

    2  erro de entrada  (arquivo, formato, imagem)

    3  erro de ambiente (dependência, artefato, memória)



Leia o MODEL_CARD.md antes de interpretar qualquer número. Resumo do que

importa: o score é probabilístico, o FPR depende fortemente do tipo de

fotografia, e o resultado não é prova de origem.

"""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

def _raiz_do_pacote() -> Path:
    """Acha o diretorio que contem `aida_p0/`, sem assumir profundidade.



    O CLI e distribuido em dois arranjos: `release/predict.py` no repositorio de

    pesquisa e `scripts/predict.py` no pacote do Hugging Face. Um caminho fixo

    so funcionaria num dos dois.

    """
    aqui = Path(__file__).resolve()
    for base in (aqui.parent, *aqui.parents):
        for candidato in (base, base / "src"):
            if (candidato / "aida_p0" / "__init__.py").exists():
                return candidato
    raise SystemExit(
        "ERRO: nao encontrei o pacote `aida_p0`. Rode este script de dentro do "
        "pacote do AIDA (o diretorio que contem `aida_p0/` e `models/`).")


sys.path.insert(0, str(_raiz_do_pacote()))

from aida_p0 import AidaP0, erros                                # noqa: E402

AVISO = ("AIDA e um detector estatistico. O resultado NAO e prova de origem "
         "nem de fraude, e o FPR varia muito por dominio (ver MODEL_CARD).")


def texto(r) -> str:
    marca = "!" if r.decisao_politica == "INCONCLUSIVO" else " "
    linhas = [
        f"arquivo    : {Path(r.arquivo).name}",
        f"score_ia   : {r.score_ia:.6f}",
        f"classe     : {r.classe}",
        f"threshold  : {r.threshold!r}",
        f"decisao  {marca} : {r.decisao_politica}",
        f"sensores   : clip {r.score_clip:.6f} | forense {r.score_forense:.6f} "
        f"| rigid {r.score_rigid:.6f}",
        f"desacordo  : {r.desacordo_entre_sensores:.6f}   "
        f"qualidade: {r.qualidade:.4f}",
        f"tempo      : {r.segundos:.2f} s",
    ]
    if r.motivos:
        linhas.append("motivos    : " + "; ".join(r.motivos))
    return "\n".join(linhas)


def main(argv: list[str] | None = None) -> int:
    ap = argparse.ArgumentParser(
        description="AIDA P0 — deteccao de imagens geradas por IA",
        epilog=AVISO)
    ap.add_argument("imagens", nargs="+", help="caminho(s) de imagem")
    ap.add_argument("--json", action="store_true",
                    help="uma linha JSON por imagem (JSONL)")
    ap.add_argument("--models-dir", default=None,
                    help="diretorio dos artefatos (padrao: ./models)")
    ap.add_argument("--sem-verificar-hashes", action="store_true",
                    help="pula a conferencia SHA-256 dos artefatos")
    ap.add_argument("--verbose", action="store_true")
    args = ap.parse_args(argv)

    try:
        aida = AidaP0(models_dir=args.models_dir,
                      verificar_hashes=not args.sem_verificar_hashes,
                      verbose=args.verbose)
    except erros.AidaError as e:
        print(f"ERRO: {e}", file=sys.stderr)
        return e.codigo_saida

    pior = 0
    for i, caminho in enumerate(args.imagens):
        try:
            r = aida.analisar(caminho)
        except erros.AidaError as e:
            print(f"ERRO [{caminho}]: {e}", file=sys.stderr)
            pior = max(pior, e.codigo_saida)
            continue
        if args.json:
            print(json.dumps(r.to_dict(), ensure_ascii=False))
        else:
            if i:
                print()
            print(texto(r))

    if not args.json:
        print(f"\n{AVISO}", file=sys.stderr)
    return pior


if __name__ == "__main__":
    raise SystemExit(main())