Samarth043 commited on
Commit
4de2b70
路
verified 路
1 Parent(s): f412e6a

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +51 -25
index.html CHANGED
@@ -15,7 +15,7 @@ img{max-width:100%;border-radius:10px;margin-top:8px}
15
  h2{margin:0 0 6px;font-size:24px}
16
  h3{margin:16px 0 4px;font-size:15px;color:#93a3b1;font-weight:600}
17
  #sub{color:#c5d0da;margin:0}
18
- .bar{height:12px;background:#2c3844;border-radius:6px;overflow:hidden;margin:8px 0}
19
  .bar div{height:100%;background:#6f93ff;width:0}
20
  li{color:#f0b04a;margin:4px 0}
21
  small{color:#93a3b1}
@@ -24,7 +24,7 @@ small{color:#93a3b1}
24
  <body>
25
  <main>
26
  <h1>Was this image made by AI?</h1>
27
- <p>Runs on your phone. Your image is never uploaded. The first check downloads the model (about 100 MB), so use Wi-Fi.</p>
28
  <input id="f" type="file" accept="image/*">
29
  <img id="p" alt="">
30
  <div id="res">
@@ -32,22 +32,31 @@ small{color:#93a3b1}
32
  <p id="sub"></p>
33
  <h3>Hidden labels</h3>
34
  <ul id="m"></ul>
35
- <h3>Pixel check</h3>
36
- <div id="pct"></div>
37
- <div class="bar"><div id="b"></div></div>
 
 
 
38
  <small id="raw"></small><br><br>
39
  <small>A probability, not proof. Detectors can be wrong, especially on new generators and screenshots.</small>
40
  </div>
41
  </main>
42
  <script type="module">
43
- import { AutoProcessor, AutoModelForImageClassification, RawImage } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3';
44
  const $ = id => document.getElementById(id);
45
- const MODEL = 'buildborderless/CommunityForensics-DeepfakeDet-ViT';
46
- let processor, model;
47
- async function load(){
 
48
  if(model) return;
49
- processor = await AutoProcessor.from_pretrained(MODEL);
50
- model = await AutoModelForImageClassification.from_pretrained(MODEL, { dtype: 'fp32' });
 
 
 
 
 
51
  }
52
  const TOOLS = [[/midjourney/i,'Midjourney'],[/dall[\s\-路]?e|openai/i,'OpenAI / DALL路E'],[/stable\s?diffusion|sdxl|automatic1111/i,'Stable Diffusion'],[/firefly|generative ?fill/i,'Adobe Firefly'],[/imagen|gemini|synthid/i,'Google AI'],[/leonardo\.?ai/i,'Leonardo AI'],[/comfyui/i,'ComfyUI'],[/ideogram/i,'Ideogram']];
53
  function markers(bytes){
@@ -59,44 +68,61 @@ function markers(bytes){
59
  return out;
60
  }
61
  function li(text, color){ const e = document.createElement('li'); e.textContent = text; if(color) e.style.color = color; return e; }
 
 
 
 
 
62
  $('f').onchange = async e => {
63
  const file = e.target.files[0]; if(!file) return;
64
  const url = URL.createObjectURL(file);
65
  $('p').src = url;
66
  $('res').style.display = 'block';
67
- $('v').textContent = 'Loading model, please wait...';
68
- $('sub').textContent = ''; $('pct').textContent = ''; $('b').style.width = '0'; $('m').innerHTML = ''; $('raw').textContent = '';
 
69
  try {
70
  const mk = markers(new Uint8Array(await file.arrayBuffer()));
71
- await load();
72
  $('v').textContent = 'Checking...';
73
  const image = await RawImage.read(url);
74
  const inputs = await processor(image);
75
  const { logits } = await model(inputs);
76
  const z = Array.from(logits.data);
77
- let ai;
78
- if(z.length === 1){ ai = 1 / (1 + Math.exp(-z[0])); }
79
- else { const m = Math.max(...z), ex = z.map(v => Math.exp(v - m)), s = ex.reduce((a,b) => a + b, 0); ai = ex[1] / s; }
80
- $('raw').textContent = 'Raw model score: ' + z.map(v => v.toFixed(2)).join(', ');
 
 
 
 
 
 
 
 
 
 
 
 
81
  if(mk.length){ mk.forEach(t => $('m').appendChild(li(t))); }
82
  else { $('m').appendChild(li('None found. Screenshots and forwarded images often lose their labels.', '#93a3b1')); }
 
83
  if(mk.length){
84
  $('v').textContent = 'AI markers found';
85
  $('sub').textContent = ai >= 0.5
86
- ? "The file's labels say AI, and the pixel check agrees."
87
- : "The file's labels say AI. The pixel check disagreed, which happens with some newer generators such as Gemini, so trust the labels.";
88
  } else if(ai >= 0.85){
89
  $('v').textContent = 'Likely AI-generated';
90
- $('sub').textContent = 'No labels found, but the pixel check says AI.';
91
  } else if(ai >= 0.5){
92
  $('v').textContent = 'Possibly AI';
93
- $('sub').textContent = 'No labels found and the pixel check is unsure.';
94
  } else {
95
  $('v').textContent = 'No AI signs found';
96
- $('sub').textContent = 'No labels found and the pixel check says real. This model can miss newer AI images, especially Gemini images and screenshots, so this is not proof.';
97
  }
98
- $('pct').textContent = 'Chance it is AI: ' + Math.round(ai*100) + '%';
99
- $('b').style.width = Math.round(ai*100) + '%';
100
  } catch(err){
101
  $('v').textContent = 'Could not analyze this image.';
102
  $('raw').textContent = String(err);
 
15
  h2{margin:0 0 6px;font-size:24px}
16
  h3{margin:16px 0 4px;font-size:15px;color:#93a3b1;font-weight:600}
17
  #sub{color:#c5d0da;margin:0}
18
+ .bar{height:12px;background:#2c3844;border-radius:6px;overflow:hidden;margin:6px 0 10px}
19
  .bar div{height:100%;background:#6f93ff;width:0}
20
  li{color:#f0b04a;margin:4px 0}
21
  small{color:#93a3b1}
 
24
  <body>
25
  <main>
26
  <h1>Was this image made by AI?</h1>
27
+ <p>Runs on your phone. Your image is never uploaded. The first check downloads two models (a few hundred MB), so use Wi-Fi.</p>
28
  <input id="f" type="file" accept="image/*">
29
  <img id="p" alt="">
30
  <div id="res">
 
32
  <p id="sub"></p>
33
  <h3>Hidden labels</h3>
34
  <ul id="m"></ul>
35
+ <h3>Pixel check 1</h3>
36
+ <div id="pct1"></div>
37
+ <div class="bar"><div id="b1"></div></div>
38
+ <h3>Pixel check 2</h3>
39
+ <div id="pct2"></div>
40
+ <div class="bar"><div id="b2"></div></div>
41
  <small id="raw"></small><br><br>
42
  <small>A probability, not proof. Detectors can be wrong, especially on new generators and screenshots.</small>
43
  </div>
44
  </main>
45
  <script type="module">
46
+ import { pipeline, AutoProcessor, AutoModelForImageClassification, RawImage } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3';
47
  const $ = id => document.getElementById(id);
48
+ const MODEL1 = 'buildborderless/CommunityForensics-DeepfakeDet-ViT';
49
+ const MODEL2 = 'LPX55/detection-model-1-ONNX';
50
+ let processor, model, clf2, fail2 = '';
51
+ async function load1(){
52
  if(model) return;
53
+ processor = await AutoProcessor.from_pretrained(MODEL1);
54
+ model = await AutoModelForImageClassification.from_pretrained(MODEL1, { dtype: 'fp32' });
55
+ }
56
+ async function load2(){
57
+ if(clf2 || fail2) return;
58
+ try { clf2 = await pipeline('image-classification', MODEL2, { dtype: 'fp32' }); }
59
+ catch(e){ fail2 = String(e); }
60
  }
61
  const TOOLS = [[/midjourney/i,'Midjourney'],[/dall[\s\-路]?e|openai/i,'OpenAI / DALL路E'],[/stable\s?diffusion|sdxl|automatic1111/i,'Stable Diffusion'],[/firefly|generative ?fill/i,'Adobe Firefly'],[/imagen|gemini|synthid/i,'Google AI'],[/leonardo\.?ai/i,'Leonardo AI'],[/comfyui/i,'ComfyUI'],[/ideogram/i,'Ideogram']];
62
  function markers(bytes){
 
68
  return out;
69
  }
70
  function li(text, color){ const e = document.createElement('li'); e.textContent = text; if(color) e.style.color = color; return e; }
71
+ function show(n, ai){
72
+ if(ai === null){ $('pct'+n).textContent = 'Not available'; $('b'+n).style.width = '0'; return; }
73
+ $('pct'+n).textContent = 'Chance it is AI: ' + Math.round(ai*100) + '%';
74
+ $('b'+n).style.width = Math.round(ai*100) + '%';
75
+ }
76
  $('f').onchange = async e => {
77
  const file = e.target.files[0]; if(!file) return;
78
  const url = URL.createObjectURL(file);
79
  $('p').src = url;
80
  $('res').style.display = 'block';
81
+ $('v').textContent = 'Loading models, please wait...';
82
+ $('sub').textContent = ''; $('m').innerHTML = ''; $('raw').textContent = '';
83
+ ['1','2'].forEach(n => { $('pct'+n).textContent = ''; $('b'+n).style.width = '0'; });
84
  try {
85
  const mk = markers(new Uint8Array(await file.arrayBuffer()));
86
+ await load1();
87
  $('v').textContent = 'Checking...';
88
  const image = await RawImage.read(url);
89
  const inputs = await processor(image);
90
  const { logits } = await model(inputs);
91
  const z = Array.from(logits.data);
92
+ let ai1;
93
+ if(z.length === 1){ ai1 = 1 / (1 + Math.exp(-z[0])); }
94
+ else { const m = Math.max(...z), ex = z.map(v => Math.exp(v - m)), s = ex.reduce((a,b) => a + b, 0); ai1 = ex[1] / s; }
95
+ show('1', ai1);
96
+ $('v').textContent = 'Loading second check...';
97
+ await load2();
98
+ let ai2 = null, raw2 = '';
99
+ if(clf2){
100
+ const r = await clf2(url, { top_k: 5 });
101
+ raw2 = r.map(x => x.label + ' ' + Math.round(x.score*100) + '%').join(', ');
102
+ const hit = r.find(x => /artificial|fake|synth|generat|\bai\b/i.test(x.label));
103
+ const real = r.find(x => /real|human|natural|authentic/i.test(x.label));
104
+ if(hit) ai2 = hit.score; else if(real) ai2 = 1 - real.score;
105
+ }
106
+ show('2', ai2);
107
+ $('raw').textContent = 'Check 1 raw score: ' + z.map(v => v.toFixed(2)).join(', ') + (clf2 ? ' | Check 2 output: ' + raw2 : ' | Check 2 could not load: ' + fail2.slice(0,120));
108
  if(mk.length){ mk.forEach(t => $('m').appendChild(li(t))); }
109
  else { $('m').appendChild(li('None found. Screenshots and forwarded images often lose their labels.', '#93a3b1')); }
110
+ const ai = Math.max(ai1, ai2 === null ? 0 : ai2);
111
  if(mk.length){
112
  $('v').textContent = 'AI markers found';
113
  $('sub').textContent = ai >= 0.5
114
+ ? "The file's labels say AI, and at least one pixel check agrees."
115
+ : "The file's labels say AI. Both pixel checks disagreed, which can happen with newer generators, so trust the labels.";
116
  } else if(ai >= 0.85){
117
  $('v').textContent = 'Likely AI-generated';
118
+ $('sub').textContent = 'No labels found, but a pixel check says AI.';
119
  } else if(ai >= 0.5){
120
  $('v').textContent = 'Possibly AI';
121
+ $('sub').textContent = 'No labels found and the pixel checks are unsure.';
122
  } else {
123
  $('v').textContent = 'No AI signs found';
124
+ $('sub').textContent = 'No labels found and the pixel checks say real. These models can miss newer AI images, so this is not proof.';
125
  }
 
 
126
  } catch(err){
127
  $('v').textContent = 'Could not analyze this image.';
128
  $('raw').textContent = String(err);