/* ===== Подари вторую жизнь — Photo search (AI) ===== */ const DEMOS = [ { key:'ginger', label:'Рыжий кот', photo:'1513245543132-31f507417b26', profile:{species:'cat',color:'ginger',size:'medium'} }, { key:'grey', label:'Серая кошка', photo:'1535268647677-300dbf3d78d1', profile:{species:'cat',color:'grey',size:'medium'} }, { key:'shep', label:'Овчарка', photo:'1587300003388-59208cc962cb', profile:{species:'dog',color:'brown',size:'large'} }, { key:'pup', label:'Белый щенок', photo:'1534361960057-19889db9621e', profile:{species:'dog',color:'white',size:'small'} }, ]; const COLOR_FAMILY = { ginger:'warm', brown:'warm', white:'light', grey:'cool', black:'dark', tabby:'warm', tricolor:'warm' }; function strHash(s){ let h=0; for(let i=0;i{ setSrc(PF.U(d.photo,800)); setProfile(d.profile); setPhase('ready'); }; const onFile = (file)=>{ if(!file){ return; } if(!file.type.startsWith('image/')){ setPhase('error'); return; } const r = new FileReader(); r.onload = e=>{ setSrc(e.target.result); setProfile(DEMOS[strHash(file.name||'x')%DEMOS.length].profile); setPhase('ready'); }; r.onerror = ()=> setPhase('error'); r.readAsDataURL(file); }; const startScan = ()=>{ setPhase('scanning'); setProgress(0); setStepIdx(0); setShowFeat(0); let i=0; const featT = [500,1050,1600,2150].map((d,k)=> setTimeout(()=>setShowFeat(k+1), d)); const tick = ()=>{ setStepIdx(i); setProgress(SCAN_STEPS[i].p); i++; if(isetPhase('results'), 450); } }; setTimeout(tick, 350); return ()=> featT.forEach(clearTimeout); }; const reset = ()=>{ setPhase('idle'); setSrc(null); setProfile(null); setProgress(0); }; const results = useMemo(()=>{ if(!profile) return []; return PF.animals.map(a=>({a, m:scoreAnimal(a,profile)})).sort((x,y)=>y.m-x.m); },[profile]); const featLabels = profile ? [ { ico:Icons.cat, txt: profile.species==='cat'?'Кошка':'Собака' }, { ico:Icons.image, txt: PF.colorLabel(profile.color) }, { ico:Icons.ruler, txt: PF.sizeLabel(profile.size) }, ] : []; return (
Умный поиск по фотографии

Найдём похожего на фото

Загрузите снимок питомца — например, того, кого вы ищете, — и мы подберём максимально похожих животных из базы по окрасу, размеру и чертам.

{/* IDLE — upload */} {phase==='idle' &&
или попробуйте на примере
{DEMOS.map(d=>( ))}
} {/* ERROR */} {phase==='error' &&
Выбрать другое фото}/>
} {/* READY + SCANNING */} {(phase==='ready'||phase==='scanning') &&
ваше фото {phase==='scanning' && } {/* scan frame brackets */} {phase==='scanning' && }
{phase==='ready' &&
} {phase==='scanning' &&
{SCAN_STEPS[stepIdx].t}
}
} {/* RESULTS */} {phase==='results' &&
Распознали на вашем фото
{featLabels.map((f,i)=>{f.txt})}

Похожие подопечные

Отсортированы по совпадению с вашим фото

{results.map(({a,m},i)=>)}
}
); } function ScanOverlay({ showFeat }){ const regions = [ { x:44, y:30, w:32, h:28, label:'морда' }, { x:38, y:6, w:46, h:22, label:'уши' }, { x:26, y:54, w:54, h:30, label:'окрас' }, { x:20, y:72, w:64, h:24, label:'телосложение' }, ]; return ( <>
{regions.map((r,i)=> i
{r.label}
)} ); } const ScanBrackets = () => ( <> {[['0','0','tl'],['0','100%','tr'],['100%','0','bl'],['100%','100%','br']].map((c,i)=>( ))} ); window.PhotoSearchScreen = PhotoSearchScreen;