1import{t as l,r as h,j as t,L as m,C as K,B as x,X as V,a3 as Z,e as tt,d as r}from"./index-DufAJSpz-1791121559443.js";import{u as et}from"./useAuth-DNK4_ykr-1791121559573.js";import{A as at,S as st,D as rt}from"./AppNavigation-C_uxMeZf-1791121559573.js";import{A as ct}from"./AuthModal-CdWDlSv7-1791121559639.js";import{P as it}from"./plus-BazNvcge-1791121559585.js";import{S as O}from"./star-Di3aPj94-1791121559589.js";import{T as nt}from"./trash-2-D0tkdWBu-1791121559589.js";import{U as ot}from"./upload-DvUah65g-1791121559585.js";import{W as lt}from"./wand-sparkles-BbSG4asc-1791121559649.js";import"./images-CMWjpk_j-1791121559573.js";import"./video-Cm5hp4uj-1791121559573.js";import"./shield-D8vna_lu-1791121559574.js";const z=4;function dt(C){const d=/^data:([^;]+);base64,(.+)$/.exec(C);return d?{mime:d[1],b64:d[2]}:null}function ht(C,d=1024,c=.82){return new Promise((y,N)=>{const S=URL.createObjectURL(C),n=new Image;n.onload=()=>{URL.revokeObjectURL(S);const w=Math.min(1,d/Math.max(n.width,n.height)),u=Math.max(1,Math.round(n.width*w)),v=Math.max(1,Math.round(n.height*w)),p=document.createElement("canvas");p.width=u,p.height=v;const g=p.getContext("2d");if(!g){N(new Error("Canvas not available"));return}g.drawImage(n,0,0,u,v),y(p.toDataURL("image/jpeg",c))},n.onerror=()=>{URL.revokeObjectURL(S),N(new Error("Could not read image"))},n.src=S})}function wt(){const{loading:C,isAuthenticated:d}=et(),c=l.characters.list.useQuery(void 0,{enabled:d}),y=l.characters.createProfile.useMutation(),N=l.characters.addPhotos.useMutation(),S=l.characters.deletePhoto.useMutation(),n=l.characters.deleteProfile.useMutation(),w=l.characters.setDefault.useMutation(),u=l.characters.startTraining.useMutation(),v=l.characters.trainingStatus.useMutation(),p=l.characters.generateTest.useMutation(),[g,U]=h.useState(""),[q,D]=h.useState(null),[R,T]=h.useState({done:0,total:0}),[I,Q]=h.useState({}),[M,W]=h.useState({}),[L,$]=h.useState(null),E=h.useRef({}),k=c.data?.profiles||[],Y=k.map(e=>`${e.id}:${e.trainingStatus}`).join(",");h.useEffect(()=>{const e=k.filter(i=>i.trainingStatus==="training");if(e.length===0)return;let s=!1;const o=setInterval(async()=>{for(const i of e)try{await v.mutateAsync({profileId:i.id})}catch{}s||await c.refetch()},12e3);return()=>{s=!0,clearInterval(o)}},[Y]);const F=async(e,s)=>{if(s<6){r.error("Add at least 6 photos before training");return}try{await u.mutateAsync({profileId:e}),await c.refetch(),r.success("Training started â this takes a few minutes. You can leave this page.")}catch(a){r.error(a?.message||"Couldn't start training")}},B=async e=>{$(e);try{const s=await p.mutateAsync({profileId:e,prompt:I[e]?.trim()||void 0});W(a=>({...a,[e]:s.dataUrl}))}catch(s){r.error(s?.message||"Couldn't generate")}finally{$(null)}},G=async()=>{if(!g.trim()){r.error("Give your character a name (e.g. âMeâ)");return}try{await y.mutateAsync({name:g.trim()}),U(""),await c.refetch(),r.success("Character created â now add your photos")}catch(e){r.error(e?.message||"Couldn't create character")}},_=async(e,s)=>{if(!s||s.length===0)return;const a=Array.from(s);D(e),T({done:0,total:a.length});try{const o=[];for(const f of a)try{const j=await ht(f),b=dt(j);b&&o.push({b64:b.b64,mime:b.mime})}catch{}if(o.length===0){r.error("Couldn't read those images. Try JPG or PNG files.");return}let i=0,P=0,A=0;for(let f=0;f<o.length;f+=z){const j=o.slice(f,f+z);try{const b=await N.mutateAsync({profileId:e,photos:j});P+=b.skipped||0,i+=j.length}catch{A+=j.length}T({done:i+A,total:o.length})}await c.refetch(),i===0?r.error("Upload failed â nothing saved. Please try again in a moment."):A>0?r.warning(`Added ${i} photo${i===1?"":"s"}; ${A} failed. Click "Add photos" again to retry the rest.`):P>0?r.warning(`Added photos â ${P} skipped (40-photo limit reached).`):r.success(`Added ${i} photo${i===1?"":"s"}`)}finally{D(null),T({done:0,total:0})}},H=async e=>{try{await S.mutateAsync({photoId:e}),await c.refetch()}catch(s){r.error(s?.message||"Couldn't delete photo")}},J=async(e,s)=>{if(window.confirm(`Delete character â${s}
1â and all its photos? This can't be undone.`))try{await n.mutateAsync({profileId:e}),await c.refetch(),r.success("Character deleted")}catch(a){r.error(a?.message||"Couldn't delete character")}},X=async e=>{try{await w.mutateAsync({profileId:e}),await c.refetch()}catch(s){r.error(s?.message||"Couldn't set default")}};return C?t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:207",className:"min-h-screen flex items-center justify-center",children:t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:208",className:"w-8 h-8 animate-spin text-primary"})}):d?t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:221",className:"min-h-screen bg-canvas",children:[t.jsx(at,{"data-loc":"client/src/pages/CharacterStudio.tsx:222"}),t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:224",className:"container mx-auto max-w-3xl px-4 py-10",children:[t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:225",className:"flex items-center gap-3 mb-2",children:[t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:226",className:"w-10 h-10 rounded-lg bg-gradient-to-br from-purple-500 to-fuchsia-600 flex items-center justify-center",children:t.jsx(st,{"data-loc":"client/src/pages/CharacterStudio.tsx:227",className:"w-5 h-5 text-white"})}),t.jsx("h1",{"data-loc":"client/src/pages/CharacterStudio.tsx:229",className:"text-3xl font-bold text-text-primary",children:"Character Studio"}),t.jsx("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:230",className:"px-2 py-0.5 text-[11px] font-bold rounded-full bg-amber-500/20 text-amber-400 border border-amber-500/30",children:"BETA"})]}),t.jsxs("p",{"data-loc":"client/src/pages/CharacterStudio.tsx:232",className:"text-text-secondary mb-8",children:["Upload several clear photos of yourself once, then ",t.jsx("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:233",className:"text-text-primary font-medium",children:"train a model"})," on them. Training builds a personal AI model of you (a Flux LoRA) so we can generate an ",t.jsx("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:234",className:"text-text-primary font-medium",children:"accurate"})," you in any scene â covers, Breaking News, thumbnails.",t.jsxs("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:235",className:"block mt-1 text-text-muted text-sm",children:["Tip: upload ",t.jsx("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:235",className:"text-text-primary font-medium",children:"10â15 clear, front-facing photos"})," â face to the camera, good light, a few different expressions. ",t.jsx("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:235",className:"text-text-primary font-medium",children:"Avoid side-profiles, back-of-head shots, sunglasses, and hats"})," â those make the model drift (and can change your look entirely). Training runs on fal.ai (needs FAL_KEY) and takes a few minutes."]})]}),t.jsxs(K,{"data-loc":"client/src/pages/CharacterStudio.tsx:239",className:"p-4 bg-gray-900 border-primary/30 mb-6",children:[t.jsx("label",{"data-loc":"client/src/pages/CharacterStudio.tsx:240",className:"text-sm font-medium text-text-secondary",children:"New character"}),t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:241",className:"flex gap-2 mt-1",children:[t.jsx("input",{"data-loc":"client/src/pages/CharacterStudio.tsx:242",type:"text",value:g,onChange:e=>U(e.target.value),onKeyDown:e=>{e.key==="Enter"&&G()},placeholder:"e.g. Me",className:"flex-1 px-3 py-2 text-sm rounded-lg bg-gray-950/50 border border-border text-text-primary placeholder:text-text-muted focus:border-purple-500/50 focus:outline-none"}),t.jsx(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:250",onClick:G,disabled:y.isPending,className:"bg-purple-600 hover:bg-purple-700",children:y.isPending?t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:251",className:"w-4 h-4 animate-spin"}):t.jsxs(t.Fragment,{children:[t.jsx(it,{"data-loc":"client/src/pages/CharacterStudio.tsx:251",className:"w-4 h-4 mr-1"})," Create"]})})]})]}),c.isLoading?t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:257",className:"flex justify-center py-12",children:t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:257",className:"w-6 h-6 animate-spin text-primary"})}):k.length===0?t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:259",className:"text-center py-12 text-text-muted",children:"No characters yet. Create one above to get started."}):t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:261",className:"space-y-6",children:k.map(e=>{const s=q===e.id;return t.jsxs(K,{"data-loc":"client/src/pages/CharacterStudio.tsx:265",className:"p-5 bg-gray-900 border-primary/30",children:[t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:266",className:"flex items-center justify-between mb-4",children:[t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:267",className:"flex items-center gap-2",children:[t.jsx("h3",{"data-loc":"client/src/pages/CharacterStudio.tsx:268",className:"text-lg font-bold text-text-primary",children:e.name}),e.isDefault&&t.jsxs("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:270",className:"inline-flex items-center gap-1 text-xs font-medium text-amber-400",children:[t.jsx(O,{"data-loc":"client/src/pages/CharacterStudio.tsx:271",className:"w-3.5 h-3.5 fill-amber-400"})," Default"]}),t.jsxs("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:274",className:"text-xs text-text-muted",children:["· ",e.photoCount," photo",e.photoCount===1?"":"s"]})]}),t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:276",className:"flex items-center gap-1",children:[!e.isDefault&&t.jsxs(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:278",onClick:()=>X(e.id),variant:"ghost",size:"sm",className:"text-text-muted hover:text-amber-400",children:[t.jsx(O,{"data-loc":"client/src/pages/CharacterStudio.tsx:279",className:"w-4 h-4 mr-1"})," Make default"]}),t.jsx(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:282",onClick:()=>J(e.id,e.name),variant:"ghost",size:"sm",className:"text-text-muted hover:text-red-400",children:t.jsx(nt,{"data-loc":"client/src/pages/CharacterStudio.tsx:283",className:"w-4 h-4"})})]})]}),t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:289",className:"grid grid-cols-4 sm:grid-cols-6 gap-2 mb-4",children:[e.photos.map(a=>t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:291",className:"relative group aspect-square",children:[t.jsx("img",{"data-loc":"client/src/pages/CharacterStudio.tsx:292",src:a.url,alt:"",className:"w-full h-full object-cover rounded-md border border-gray-700"}),t.jsx("button",{"data-loc":"client/src/pages/CharacterStudio.tsx:293",type:"button",onClick:()=>H(a.id),className:"absolute top-1 right-1 p-0.5 rounded-full bg-black/70 text-white opacity-0 group-hover:opacity-100 transition",title:"Remove photo",children:t.jsx(V,{"data-loc":"client/src/pages/CharacterStudio.tsx:299",className:"w-3.5 h-3.5"})})]},a.id)),e.photos.length===0&&t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:304",className:"col-span-full text-sm text-text-muted py-4 text-center",children:"No photos yet â add some below."})]}),t.jsx("input",{"data-loc":"client/src/pages/CharacterStudio.tsx:308",type:"file",accept:"image/*",multiple:!0,ref:a=>{E.current[e.id]=a},onChange:a=>{_(e.id,a.target.files),a.currentTarget.value=""},className:"hidden"}),t.jsx(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:316",onClick:()=>E.current[e.id]?.click(),disabled:s,variant:"outline",className:"w-full",children:s?t.jsxs(t.Fragment,{children:[t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:323",className:"w-4 h-4 mr-2 animate-spin"})," Uploading ",R.done,"/",R.total,"â¦"]}):t.jsxs(t.Fragment,{children:[t.jsx(ot,{"data-loc":"client/src/pages/CharacterStudio.tsx:325",className:"w-4 h-4 mr-2"})," Add photos"]})}),t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:330",className:"mt-4 pt-4 border-t border-gray-800",children:e.trainingStatus==="ready"?t.jsxs(t.Fragment,{children:[t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:333",className:"flex items-center justify-between mb-3",children:[t.jsxs("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:334",className:"inline-flex items-center gap-1.5 text-sm font-semibold text-emerald-400",children:[t.jsx(Z,{"data-loc":"client/src/pages/CharacterStudio.tsx:335",className:"w-4 h-4"})," Trained â an accurate AI you is ready"]}),t.jsx(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:337",onClick:()=>F(e.id,e.photoCount),variant:"ghost",size:"sm",disabled:u.isPending,className:"text-text-muted hover:text-text-primary",children:"Retrain"})]}),t.jsx("label",{"data-loc":"client/src/pages/CharacterStudio.tsx:341",className:"text-xs font-medium text-text-muted",children:"Test your model â start with how you look, then the scene (so it doesn't drift)"}),t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:342",className:"flex gap-2 mt-1",children:[t.jsx("input",{"data-loc":"client/src/pages/CharacterStudio.tsx:343",type:"text",value:I[e.id]||"",onChange:a=>Q(o=>({...o,[e.id]:a.target.value})),onKeyDown:a=>{a.key==="Enter"&&B(e.id)},placeholder:"e.g. a man with short dark hair, smiling, on a podcast set",className:"flex-1 px-3 py-2 text-sm rounded-lg bg-gray-950/50 border border-border text-text-primary placeholder:text-text-muted focus:border-purple-500/50 focus:outline-none"}),t.jsx(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:351",onClick:()=>B(e.id),disabled:L===e.id,className:"bg-purple-600 hover:bg-purple-700 shrink-0",children:L===e.id?t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:352",className:"w-4 h-4 animate-spin"}):t.jsxs(t.Fragment,{children:[t.jsx(lt,{"data-loc":"client/src/pages/CharacterStudio.tsx:352",className:"w-4 h-4 mr-1"})," Generate"]})})]}),M[e.id]&&t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:356",className:"mt-3",children:[t.jsx("img",{"data-loc":"client/src/pages/CharacterStudio.tsx:357",src:M[e.id],alt:"Trained test",className:"w-48 rounded-lg border border-purple-500/30"}),t.jsxs("a",{"data-loc":"client/src/pages/CharacterStudio.tsx:358",href:M[e.id],download:`${e.name}-test.jpg`,className:"inline-flex items-center gap-1 text-xs text-purple-400 hover:text-purple-300 mt-1",children:[t.jsx(rt,{"data-loc":"client/src/pages/CharacterStudio.tsx:359",className:"w-3 h-3"})," Download"]})]})]}):e.trainingStatus==="training"?t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:365",className:"inline-flex items-center gap-2 text-sm text-amber-400",children:[t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:366",className:"w-4 h-4 animate-spin"})," Training your model⦠(a few minutes â you can leave this page)"]}):t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:369",className:"flex items-center justify-between gap-3",children:[t.jsxs("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:370",className:"text-sm text-text-muted",children:[e.trainingStatus==="failed"?t.jsx("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:372",className:"text-red-400",children:"Training failed â please try again."}):"Train a model on these photos to generate an accurate AI version of you in any sce
1ne.",e.photoCount<6&&t.jsxs("span",{"data-loc":"client/src/pages/CharacterStudio.tsx:374",className:"block text-xs mt-0.5",children:["Add at least 6 photos to train (you have ",e.photoCount,")."]})]}),t.jsx(x,{"data-loc":"client/src/pages/CharacterStudio.tsx:376",onClick:()=>F(e.id,e.photoCount),disabled:u.isPending||e.photoCount<6,className:"bg-purple-600 hover:bg-purple-700 shrink-0",children:u.isPending?t.jsx(m,{"data-loc":"client/src/pages/CharacterStudio.tsx:377",className:"w-4 h-4 animate-spin"}):t.jsxs(t.Fragment,{children:[t.jsx(tt,{"data-loc":"client/src/pages/CharacterStudio.tsx:377",className:"w-4 h-4 mr-1"})," ",e.trainingStatus==="failed"?"Retry training":"Train on my photos"]})})]})})]},e.id)})})]})]}):t.jsx("div",{"data-loc":"client/src/pages/CharacterStudio.tsx:214",className:"min-h-screen flex flex-col items-center justify-center px-4 py-12 bg-canvas",children:t.jsx(ct,{"data-loc":"client/src/pages/CharacterStudio.tsx:215",onSuccess:()=>window.location.reload()})})}export{wt 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.