PageSourceSearch

https://unmodel.ai/assets/TagSensePanel-Cu_igByI.js

js unmodel.ai collected 2026-10-05 15:56:54 UTC 17,589 bytes, 1 lines download raw bytes

1import{dI as De,p as Oe,eg as Ue,a as t,a$ as ue,b1 as pe,v as h,im as ge,jw as xe,jx as fe,j as e,jy as He,S as w,c6 as $e,n as Me,cn as Ge,L as W,dd as Je,cz as D,cA as ye,cB as je,aQ as Ve,cC as O,bx as f,ck as q,jz as Be,e6 as We,fA as qe,C as Ke,hH as Qe,em as be,ek as Ye,eK as Ze,el as Xe,eJ as es}from"./try-on-links-D-kskELd.js";import{u as ss}from"./JobSubmissionAnimation-26bEzvbb.js";import{S as ve}from"./separator-BeQg1nq1.js";import{T as as,a as ts,b as K,c as Q}from"./tabs-BLT7ss3V.js";import{I as rs}from"./IngestImportHint-COlaj2_4.js";import{I as ns}from"./IngestImageSlot-BQuhkpMk.js";import{C as is}from"./CatalogRecentOutputStrip-a0UGE4wN.js";import{i as Y}from"./ingestJourneyTheme-B55h8ZcE.js";import{u as ls}from"./useInView-CiwQ_Jf5.js";import"./ingestDrag-D0-x4mdv.js";const bs=De.memo(function({initialImageUrl:p,sessionId:Ne,onAnalysisComplete:_,onResultReady:Z,onClearResult:R,showHistory:S=!0,addGlobalOperation:X,removeGlobalOperation:ee}){const{toast:u}=Oe(),{poll:we}=Ue(),[C,U]=t.useState("capture"),[k,v]=t.useState(null),[o,T]=t.useState(null),[z,se]=t.useState(!1),[l,N]=t.useState(null),Se=ue(s=>s.resultsGalleryOpen);ue(s=>s.setResultsGalleryOpen);const[ae,te]=t.useState([]),[ke,re]=t.useState(1),[H,Te]=t.useState(!0),[I,ne]=t.useState(!1),[Ce,ie]=t.useState(!1),[le,cs]=t.useState("environment"),[$,oe]=t.useState(null),M=t.useRef(null),{triggerAnimation:Ie,AnimationComponent:Ee}=ss("tagsense"),y=pe(s=>s.setHasSource),j=pe(s=>s.setTagsenseJourney),ce=ls(M,{rootMargin:"0px 0px -72px 0px"}),E=t.useRef(null),G=t.useRef(null),de=t.useRef(null),J=10,[L,V]=t.useState(null);t.useEffect(()=>{p&&p!==L&&(T(p),V(p),v(null),(async()=>{try{h.debug("🔄 TagSense: Fetching image via proxy:",p);const r=`/api/proxy/image?url=${encodeURIComponent(p)}`,a=await fetch(r,{credentials:"include"});if(!a.ok)throw new Error(`Proxy fetch failed: ${a.status}`);const n=await a.blob(),c=p.split("/").pop()||"product-image.jpg",d=new File([n],c,{type:n.type||"image/jpeg"});v(d),h.debug("✅ TagSense: Image loaded successfully via proxy")}catch(r){h.warn("⚠️ TagSense: Image fetch failed, will retry on analyze:",r)}})())},[p,L]),t.useEffect(()=>{!p&&L&&(T(null),v(null),V(null),N(null))},[p,L]);const Fe=t.useCallback(async()=>{try{const s=await navigator.mediaDevices.getUserMedia({video:{facingMode:le}});oe(s),ie(!0),E.current&&(E.current.srcObject=s)}catch(s){h.error("Failed to start camera:",s),u({title:"Camera Error",description:"Failed to access camera. Please check permissions.",variant:"destructive"})}},[le,u]),F=t.useCallback(()=>{$&&($.getTracks().forEach(s=>s.stop()),oe(null),ie(!1))},[$]),Ae=t.useCallback(()=>{if(E.current&&G.current){const s=E.current,r=G.current,a=r.getContext("2d");a&&(r.width=s.videoWidth,r.height=s.videoHeight,a.drawImage(s,0,0),r.toBlob(n=>{if(n){const c=new File([n],"captured-photo.jpg",{type:"image/jpeg"});v(c),T(r.toDataURL("image/jpeg")),F(),u({title:"Photo Captured",description:"Photo captured successfully. Click 'Create Tags' to analyze fashion."})}},"image/jpeg",.8))}},[F,u]),A=t.useCallback(()=>{v(null),T(null),V(null),y("tagsense",!1)},[y]),Pe=t.useCallback(()=>{N(null),j({hasResult:!1}),R?.()},[j,R]),_e=t.useCallback(()=>{A(),N(null),j({hasResult:!1}),R?.()},[A,j,R]);t.useEffect(()=>{j({hasResult:!!l,generateInView:ce})},[l,ce,j]),t.useEffect(()=>()=>{j({hasResult:!1,generateInView:!1})},[j]);const B=l?.imageUrl||o,me=t.useCallback(s=>{ge(xe(s,"Tag analysis","image",{toolType:"tagsense"})),Z?.(s)},[Z]),Re=t.useCallback(s=>{if(!s.type.startsWith("image/")){u({title:"Invalid File",description:"Please select a valid image file.",variant:"destructive"});return}v(s);const r=new FileReader;r.onload=a=>{T(a.target?.result)},r.readAsDataURL(s),y("tagsense",!0),u({title:"Image Selected",description:"Image uploaded successfully. Click 'Create Tags' to analyze fashion."})},[u,y]);t.useEffect(()=>{const s=r=>{const a=r.detail;if(a.contextId==="tagsense"){if(!a.url){A();return}v(a.file),T(a.url),y("tagsense",!0)}};return window.addEventListener(fe,s),()=>window.removeEventListener(fe,s)},[A,y]),t.useEffect(()=>{y("tagsense",!!o)},[o,y]);const ze=async()=>
1{if(h.debug("🔍 TagSense: analyzeImage called",{hasUploadedImage:!!k,hasImagePreview:!!o,imagePreviewUrl:o?.substring(0,100)}),!k&&!o){h.warn("❌ TagSense: No image available"),u({title:"No Image",description:"Please upload or capture an image first.",variant:"destructive"});return}se(!0),N(null);let s=null,r=null;try{X&&(s=X({type:"tagsense",description:"Fashion image analysis"}));let a=Ne;if(!a){const m=await(await fetch("/api/sessions",{method:"GET",credentials:"include"})).json();if(m&&m.length>0){const g=m.filter(b=>b.mode==="tool");g.length>0&&(a=g.sort((b,Le)=>new Date(Le.created_at).getTime()-new Date(b.created_at).getTime())[0].id)}}let n=k;if(!n&&o)try{h.debug("🔄 TagSense analyze: Fetching image via proxy:",o);const i=`/api/proxy/image?url=${encodeURIComponent(o)}`,m=await fetch(i,{credentials:"include"});if(!m.ok)throw new Error(`Proxy fetch failed: ${m.status}`);const g=await m.blob(),b=o.split("/").pop()||"product-image.jpg";n=new File([g],b,{type:g.type||"image/jpeg"}),h.debug("✅ TagSense analyze: Image loaded via proxy")}catch(i){throw h.error("Error fetching image for analysis:",i),new Error("Failed to load image for analysis. Please try uploading the image directly.")}if(!n)throw new Error("No image available for analysis");const c=new FormData;c.append("image",n),a&&c.append("sessionId",a);try{const i=await qe.ensureToken();i&&c.append("_csrf",i)}catch(i){h.warn("⚠️ Could not add CSRF token to FormData:",i)}const d=await Ke("/api/tagsense/analyze",{method:"POST",body:c});if(d.status===402){const i=await d.json();throw new Error(i.message||"Insufficient credits")}if(!d.ok){const i=await d.json();throw new Error(i.error||i.message||"Failed to analyze image")}if(d.status===202){const i=await d.json(),m=i.jobId||i.data?.jobId||(i.data&&typeof i.data=="object"&&"jobId"in i.data?i.data.jobId:null);if(!m)throw new Error("Job ID not received from server");r=String(m),Qe(m,40,"tagsense");const g=await we(m,{maxPollTime:3e5}),b={...g.analysis,imageUrl:g.imageUrl};N(b),me(g.imageUrl),be(),u({title:"Analysis Complete",description:`Fashion analysis completed with ${g.analysis.confidence}% confidence`}),_&&_(b),P({append:!1});return}const x=await d.json();if(!x.analysis)throw new Error("Invalid response format: missing analysis data");const he={...x.analysis,imageUrl:x.imageUrl};N(he),me(x.imageUrl),be(),u({title:"Analysis Complete",description:`Fashion analysis completed with ${x.analysis.confidence}% confidence`}),_&&_(he),P({append:!1})}catch(a){h.error("Analysis error:",a),Ye(a,{action:"tagsense_analyze",serverOwned:!!r&&es(a),expected:Xe(a),metadata:{...r?{jobId:r}:{},...Ze(a)}}),u({title:"Analysis Failed",description:a instanceof Error?a.message:"Failed to analyze image",variant:"destructive"})}finally{se(!1),s&&ee&&ee(s)}},P=async s=>{try{if(I)return;ne(!0);const a=((s?.append?ke:1)-1)*J,n=await fetch(`/api/tagsense/history?limit=${J}&offset=${a}`,{credentials:"include"});if(n.ok){const c=await n.json(),d=Array.isArray(c.data?.history)?c.data.history:Array.isArray(c.history)?c.history:[];Te(d.length===J),s?.append?(te(x=>[...x,...d]),re(x=>x+1)):(te(d),re(2))}}catch(r){h.error("Failed to fetch history:",r)}finally{ne(!1)}};return t.useEffect(()=>{C==="history"&&S&&P({append:!1})},[C,S]),t.useEffect(()=>{if(C!=="history"||!S)return;const s=de.current;if(!s)return;const r=new IntersectionObserver(a=>{a[0].isIntersecting&&H&&!I&&P({append:!0})},{root:null,rootMargin:"200px",threshold:.1});return r.observe(s),()=>r.disconnect()},[C,S,H,I]),t.useEffect(()=>()=>{F()},[F]),e.jsxs("div",{className:"space-y-6",children:[Ee,e.jsx(rs,{}),e.jsxs(as,{value:C,onValueChange:s=>U(s),className:"w-full",children:[e.jsxs(ts,{className:"theme-tool-tab-list grid w-full grid-cols-3 shadow-inner",children:[e.jsx(K,{value:"capture",className:"theme-tool-tab px-2 sm:px-3 py-2 text-xs sm:text-sm font-medium sm:font-semibold",children:"Capture & Upload"}),e.jsx(K,{value:"results",className:"theme-tool-tab px-2 sm:px-3 py-2 text-xs sm:text-sm font-medium sm:font-semibold",children:"Analysis Results"}),S&&e.jsx(K,{value:"history",className:"theme-tool-tab px-2 sm:px-3 py-2 text-xs sm:text-sm font-medium sm:font-semibold",children:"History"})]}),e.jsx(Q,{value:"capture",className:"mt-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsx(ns,{contextId:"tagsense",slotKey:"source",variant:"tile",label:"Product image",preview:o,required:!0,highlighted:!0,disabled:z,inputId:"tagsense-image-upload",chooseFileLabel:He,onFileSelect:Re,onRemove:A,emptyContent:Ce?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"relative",children:[e.jsx("video",{ref:E,autoPlay:!0,playsInl
1ine:!0,className:"mx-auto max-h-40 w-full rounded-lg object-contain"}),e.jsx("canvas",{ref:G,className:"hidden"})]}),e.jsxs("div",{className:"flex justify-center gap-3",children:[e.jsx(w,{onClick:Ae,className:"theme-action rounded-xl px-6 py-2.5 text-sm font-medium",children:"Capture Photo"}),e.jsx(w,{onClick:F,variant:"outline",className:"theme-action",children:"Cancel"})]})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsx($e,{className:Me("mx-auto h-10 w-10",Y.slotIcon)}),e.jsxs("div",{children:[e.jsx("p",{className:Y.slotDescription,children:"Choose photo"}),e.jsx("p",{className:"text-sm theme-muted",children:"PNG, JPG, GIF up to 10MB · or drop here"})]}),e.jsxs("div",{className:"flex justify-center gap-3",children:[e.jsxs(w,{onClick:Fe,className:"theme-action flex items-center gap-2 rounded-xl px-6 py-2.5 text-sm font-medium transition-all duration-200",children:[e.jsx(Ge,{className:"h-4 w-4"}),"Use Camera"]}),e.jsx(w,{onClick:()=>document.getElementById("tagsense-image-upload")?.click(),className:Y.ingestActionPrimary,children:"Choose photo"})]})]}),children:o?e.jsxs(e.Fragment,{children:[e.jsx("img",{src:o,alt:"Selected fashion item",className:"mx-auto max-h-40 w-full rounded-lg object-contain"}),k?.name&&e.jsx("p",{className:"text-sm theme-muted",children:k.name})]}):void 0}),e.jsx("div",{className:"flex gap-3 justify-center",children:e.jsx(w,{ref:M,onClick:async()=>{Ie(M.current);try{await ze()}catch(s){throw s}},disabled:!k&&!o||z,className:"theme-cta flex-1 max-w-md font-medium px-6 py-3 rounded-xl disabled:opacity-50",children:z?e.jsxs(e.Fragment,{children:[e.jsx(W,{size:"sm",variant:"primary",className:"mr-2"}),"Analyzing..."]}):e.jsxs(e.Fragment,{children:[e.jsx(Je,{className:"mr-2 h-4 w-4"}),"Create Tags"]})})}),z&&e.jsxs("div",{className:"text-center space-y-4",children:[e.jsx("div",{className:"flex items-center justify-center",children:e.jsx(W,{size:"lg",variant:"accent"})}),e.jsx("p",{className:"theme-ink",children:"Analyzing fashion image..."}),e.jsx("p",{className:"text-sm theme-muted",children:"This may take a few moments"})]})]})}),B&&l&&!Se&&e.jsx(is,{images:[{imageUrl:B}],readyLabel:"Tags ready",subtitle:"Tap to view analysis",sectionAriaLabel:"Recent TagSense output",onViewGallery:()=>ge(xe(B,"Tag analysis","image",{toolType:"tagsense"})),secondaryCtaLabel:"View full analysis",onSecondaryCta:()=>U("results"),onClear:Pe,onStartNew:_e}),e.jsx(Q,{value:"results",className:"mt-6",children:l?e.jsxs(D,{className:"theme-group overflow-hidden",children:[e.jsx(ye,{children:e.jsxs(je,{className:"flex items-center gap-2 theme-ink",children:[e.jsx(Ve,{className:"h-5 w-5"}),"Analysis Results"]})}),e.jsxs(O,{className:"space-y-6",children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2 theme-ink",children:"Primary Tag"}),e.jsx("p",{className:"theme-ink",children:l.primaryTag})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2 theme-ink",children:"Confidence"}),e.jsxs(f,{variant:"secondary",className:"theme-chip-idle theme-ink",children:[l?.confidence??0,"%"]})]}),l.imageUrl&&e.jsx("div",{className:"flex-shrink-0 ml-2",children:e.jsx("img",{src:l.imageUrl,alt:l.primaryTag,className:"w-24 h-24 object-cover rounded-lg border border-brand-border",onError:s=>{s.currentTarget.style.display="none"}})})]})]}),e.jsx(ve,{className:"bg-brand-border"}),e.jsxs("div",{className:"space-y-4",children:[e.jsx("h3",{className:"text-lg font-semibold theme-ink",children:"Fashion Tags"}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:l?.tags&&typeof l.tags=="object"?Object.entries(l.tags).map(([s,r])=>Array.isArray(r)&&r.length>0?e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm capitalize theme-ink",children:s.replace(/_/g," ")}),e.jsx("div",{className:"flex flex-wrap gap-1",children:r.map((a,n)=>e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:a},n))})]},s):null):e.jsx("p",{className:"theme-muted text-sm",children:"No tags available"})})]}),e.jsx(ve,{className:"bg-brand-border"}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2 theme-ink",children:"Description"}),e.jsx("p",{className:"theme-ink",children:l.description})]}),l.seo_title&&e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2 theme-ink",children:"SEO Title"}),e.jsx("p",{className:"theme-ink",children:l.seo_title})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2 theme-ink",children:"SEO Description"}),e.jsx("p",{className:"theme-ink",children:l.seo_description})]}),l.professional_tags.length>0&&e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold mb-2 theme-ink",children:"Professional Tags"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:l.professional_tags.map((s,r)=>e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:s},r))})]})]})]})]}):e.jsx(D,{className:"theme-group overflow-hidden",children:e.jsxs(O,{className:"text-center py-12",children:[e.jsx(q,{className:"h-16 w-16 mx-auto theme-muted mb-4"}
1),e.jsx("p",{className:"theme-ink",children:"No analysis results yet. Capture or upload an image to get started."})]})})}),S&&e.jsx(Q,{value:"history",className:"mt-6",children:e.jsxs(D,{className:"theme-group overflow-hidden",children:[e.jsx(ye,{children:e.jsxs(je,{className:"flex items-center gap-2 theme-ink",children:[e.jsx(Be,{className:"h-5 w-5"}),"Analysis History"]})}),e.jsx(O,{children:I?e.jsxs("div",{className:"text-center theme-muted py-8",children:[e.jsx(W,{size:"lg",variant:"primary",className:"mx-auto mb-2"}),e.jsx("p",{children:"Loading history..."})]}):ae.length>0?e.jsxs("div",{className:"space-y-4",children:[ae.map((s,r)=>e.jsx("div",{className:"p-4 border border-brand-border rounded-lg hover:bg-brand-wash transition-colors theme-ink",children:e.jsxs("div",{className:"flex items-start gap-4",children:[s.image_url&&e.jsx("div",{className:"flex-shrink-0",children:e.jsx(We,{src:s.image_url,thumbnailSrc:s.thumbnail_url||void 0,alt:s.primary_tag,width:96,height:96,className:"w-24 h-24 object-cover rounded-lg border border-brand-border",fallbackIcon:e.jsx(q,{className:"w-8 h-8 theme-muted"}),quality:85})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("h4",{className:"font-medium mb-2 theme-ink",children:s.primary_tag}),e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:s.tags.category?.[0]||"Fashion"}),e.jsxs(f,{variant:"secondary",className:"text-xs theme-chip-idle theme-ink",children:[s.confidence,"% confidence"]}),e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:new Date(s.created_at).toLocaleDateString()})]}),e.jsx("p",{className:"text-sm theme-muted line-clamp-2",children:s.description}),s.tags&&e.jsxs("div",{className:"mt-3 flex flex-wrap gap-1",children:[s.tags.color?.slice(0,3).map((a,n)=>e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:a},`color-${n}`)),s.tags.material?.slice(0,2).map((a,n)=>e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:a},`material-${n}`)),s.tags.occasion?.slice(0,2).map((a,n)=>e.jsx(f,{variant:"outline",className:"text-xs theme-chip-idle theme-ink border-brand-border",children:a},`occasion-${n}`))]})]}),e.jsx(w,{variant:"ghost",size:"sm",onClick:()=>{const a={primaryTag:s.primary_tag,tags:s.tags,confidence:s.confidence,description:s.description,seo_title:s.seo_title,seo_description:s.seo_description,professional_tags:s.professional_tags,imageUrl:s.image_url};N(a),U("results")},className:"theme-action",children:"View Details"})]})},s.id||`history-item-${r}`)),e.jsx("div",{ref:de,className:"h-6"}),I&&e.jsx("div",{className:"text-center theme-muted",children:"Loading…"}),H&&e.jsx("div",{className:"flex justify-center pt-2",children:e.jsx(w,{variant:"outline",onClick:()=>P({append:!0}),className:"theme-action rounded-xl px-6 py-2.5 text-sm font-medium transition-all duration-200",children:"Load More"})})]}):e.jsx(D,{className:"theme-group overflow-hidden",children:e.jsxs(O,{className:"text-center py-12",children:[e.jsx(q,{className:"h-16 w-16 mx-auto theme-muted mb-4"}),e.jsx("p",{className:"theme-ink",children:"No analysis history yet. Capture or upload an image to get started."})]})})})]})})]})]})});export{bs as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.