Spaces:
Running
Running
Download index.html from Samarth043/Sam1: direct link, hf CLI and curl.
- Browser
- Download file 6.62 kB
-
https://huggingface.co/spaces/Samarth043/Sam1/resolve/main/index.html
- Command line
-
hf download hf://spaces/Samarth043/Sam1/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Samarth043/Sam1/resolve/main/index.html
6.62 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>AI Image Detector</title> | |
| <style> | |
| body{margin:0;font:16px/1.5 system-ui,sans-serif;background:#0f151b;color:#e8eef3} | |
| main{max-width:520px;margin:0 auto;padding:24px 16px} | |
| h1{font-size:28px;margin:8px 0} | |
| p{color:#93a3b1} | |
| input{display:block;width:100%;margin:16px 0;padding:14px;background:#18212a;border:2px dashed #2c3844;border-radius:12px;color:#e8eef3} | |
| img{max-width:100%;border-radius:10px;margin-top:8px} | |
| #res{background:#18212a;border-radius:12px;padding:16px;margin-top:16px;display:none} | |
| h2{margin:0 0 6px;font-size:24px} | |
| h3{margin:16px 0 4px;font-size:15px;color:#93a3b1;font-weight:600} | |
| #sub{color:#c5d0da;margin:0} | |
| .bar{height:12px;background:#2c3844;border-radius:6px;overflow:hidden;margin:6px 0 10px} | |
| .bar div{height:100%;background:#6f93ff;width:0} | |
| li{color:#f0b04a;margin:4px 0} | |
| small{color:#93a3b1} | |
| </style> | |
| </head> | |
| <body> | |
| <main> | |
| <h1>Was this image made by AI?</h1> | |
| <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> | |
| <input id="f" type="file" accept="image/*"> | |
| <img id="p" alt=""> | |
| <div id="res"> | |
| <h2 id="v"></h2> | |
| <p id="sub"></p> | |
| <h3>Hidden labels</h3> | |
| <ul id="m"></ul> | |
| <h3>Pixel check 1</h3> | |
| <div id="pct1"></div> | |
| <div class="bar"><div id="b1"></div></div> | |
| <h3>Pixel check 2</h3> | |
| <div id="pct2"></div> | |
| <div class="bar"><div id="b2"></div></div> | |
| <small id="raw"></small><br><br> | |
| <small>A probability, not proof. Detectors can be wrong, especially on new generators and screenshots.</small> | |
| </div> | |
| </main> | |
| <script type="module"> | |
| import { pipeline, AutoProcessor, AutoModelForImageClassification, RawImage } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3'; | |
| const $ = id => document.getElementById(id); | |
| const MODEL1 = 'buildborderless/CommunityForensics-DeepfakeDet-ViT'; | |
| const MODEL2 = 'LPX55/detection-model-2-ONNX'; | |
| let processor, model, clf2, fail2 = ''; | |
| async function load1(){ | |
| if(model) return; | |
| processor = await AutoProcessor.from_pretrained(MODEL1); | |
| model = await AutoModelForImageClassification.from_pretrained(MODEL1, { dtype: 'fp32' }); | |
| } | |
| async function load2(){ | |
| if(clf2 || fail2) return; | |
| try { clf2 = await pipeline('image-classification', MODEL2, { dtype: 'fp32' }); } | |
| catch(e){ fail2 = String(e); } | |
| } | |
| const TOOLS = [ | |
| [/\bmidjourney\b/i,'Midjourney'], | |
| [/\bopenai\b|\bdall[\s\-_·]?e\b/i,'OpenAI / DALL·E'], | |
| [/stable[\s\-_]?diffusion|stability\.ai|automatic1111|\bsdxl\b/i,'Stable Diffusion'], | |
| [/adobe firefly|\bfirefly\b|generative ?fill/i,'Adobe Firefly'], | |
| [/\bimagen\b|\bgemini\b|\bsynthid\b|google ai/i,'Google AI'], | |
| [/leonardo\.ai/i,'Leonardo AI'], | |
| [/\bcomfyui\b/i,'ComfyUI'], | |
| [/\bideogram\b/i,'Ideogram'] | |
| ]; | |
| function markers(bytes){ | |
| const full = new TextDecoder('latin1').decode(bytes), out = []; | |
| const runs = full.match(/[\x20-\x7e]{6,}/g); | |
| const readable = runs ? runs.join('\n') : ''; | |
| if(/c2pa|jumbf|contentcredentials/i.test(full)) out.push('Content Credentials (C2PA) found'); | |
| if(/algorithmicMedia/.test(full)) out.push('Marked as AI media in metadata'); | |
| TOOLS.forEach(([re,n]) => { if(re.test(readable)) out.push('Names an AI tool: ' + n); }); | |
| if(/Steps:\s*\d+,\s*Sampler|negative prompt|"class_type"/i.test(readable)) out.push('Contains a generation prompt or settings'); | |
| return out; | |
| } | |
| function li(text, color){ const e = document.createElement('li'); e.textContent = text; if(color) e.style.color = color; return e; } | |
| function show(n, ai){ | |
| if(ai === null){ $('pct'+n).textContent = 'Not available'; $('b'+n).style.width = '0'; return; } | |
| $('pct'+n).textContent = 'Chance it is AI: ' + Math.round(ai*100) + '%'; | |
| $('b'+n).style.width = Math.round(ai*100) + '%'; | |
| } | |
| $('f').onchange = async e => { | |
| const file = e.target.files[0]; if(!file) return; | |
| const url = URL.createObjectURL(file); | |
| $('p').src = url; | |
| $('res').style.display = 'block'; | |
| $('v').textContent = 'Loading models, please wait...'; | |
| $('sub').textContent = ''; $('m').innerHTML = ''; $('raw').textContent = ''; | |
| ['1','2'].forEach(n => { $('pct'+n).textContent = ''; $('b'+n).style.width = '0'; }); | |
| try { | |
| const mk = markers(new Uint8Array(await file.arrayBuffer())); | |
| await load1(); | |
| $('v').textContent = 'Checking...'; | |
| const image = await RawImage.read(url); | |
| const inputs = await processor(image); | |
| const { logits } = await model(inputs); | |
| const z = Array.from(logits.data); | |
| let ai1; | |
| if(z.length === 1){ ai1 = 1 / (1 + Math.exp(-z[0])); } | |
| 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; } | |
| show('1', ai1); | |
| $('v').textContent = 'Loading second check...'; | |
| await load2(); | |
| let ai2 = null, raw2 = ''; | |
| if(clf2){ | |
| const r = await clf2(url, { top_k: 5 }); | |
| raw2 = r.map(x => x.label + ' ' + Math.round(x.score*100) + '%').join(', '); | |
| const hit = r.find(x => /artificial|fake|synth|generat|\bai\b/i.test(x.label)); | |
| const real = r.find(x => /real|human|natural|authentic/i.test(x.label)); | |
| if(hit) ai2 = hit.score; else if(real) ai2 = 1 - real.score; | |
| } | |
| show('2', ai2); | |
| $('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)); | |
| if(mk.length){ mk.forEach(t => $('m').appendChild(li(t))); } | |
| else { $('m').appendChild(li('None found. Screenshots and forwarded images often lose their labels.', '#93a3b1')); } | |
| const ai = Math.max(ai1, ai2 === null ? 0 : ai2); | |
| if(mk.length){ | |
| $('v').textContent = 'AI markers found'; | |
| $('sub').textContent = ai >= 0.5 | |
| ? "The file's labels say AI, and at least one pixel check agrees." | |
| : "The file's labels say AI. Both pixel checks disagreed, which can happen with newer generators, so trust the labels."; | |
| } else if(ai >= 0.85){ | |
| $('v').textContent = 'Likely AI-generated'; | |
| $('sub').textContent = 'No labels found, but a pixel check says AI.'; | |
| } else if(ai >= 0.5){ | |
| $('v').textContent = 'Possibly AI'; | |
| $('sub').textContent = 'No labels found and the pixel checks are unsure.'; | |
| } else { | |
| $('v').textContent = 'No AI signs found'; | |
| $('sub').textContent = 'No labels found and the pixel checks say real. These models can miss newer AI images, so this is not proof.'; | |
| } | |
| } catch(err){ | |
| $('v').textContent = 'Could not analyze this image.'; | |
| $('raw').textContent = String(err); | |
| } | |
| }; | |
| </script> | |
| </body> | |
| </html> |