o
    @Tj                     @  s2  U d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ ddlmZ ddlmZ eeZededgZ de!d< h dZ"G dd deZ#G dd deZ$G dd deZ%d-ddZ&d.d d!Z'	"		d/d0d+d,Z(dS )1a  Wardrobe seeding: populate the unknown user's wardrobe from preset images.

Shared orchestration used by both the CLI script (scripts/seed_wardrobe.py)
and the admin HTTP endpoint (POST /api/v1/admin/seed).

Modes:
- "reset": wipe DB + storage (preserves GLOBAL_USER_ID), then seed
- "add":   keep existing data, append new garments to the unknown user

Ghost mannequin is always generated so VTON works immediately after seeding.
    )annotationsN)Callable)Path)Literal)	BaseModel)deleteselect)AsyncSession)GLOBAL_USER_IDsettings)FaceEmbedding)Garment)User)GarmentServicez,/home/ubuntu/ootd-poc/resources/men_garmentsz./home/ubuntu/ootd-poc/resources/women_garments
list[Path]DEFAULT_RESOURCE_DIRS>   .jpg.png.jpeg.webpc                   @  s.   e Zd ZU ded< ded< ded< ded< dS )ResetSummaryintdeleted_garmentsdeleted_facesdeleted_usersdeleted_filesN__name__
__module____qualname____annotations__ r!   r!   9/home/ubuntu/htdocs/ootd-api/app/services/seed_service.pyr   *   s
   
 r   c                   @  s&   e Zd ZU ded< ded< ded< dS )	SeedErrorstrfilez#Literal['read', 'analyze', 'ghost']stagemessageNr   r!   r!   r!   r"   r#   1   s   
 r#   c                   @  sR   e Zd ZU ded< dZded< dZded< dZded< g Zded	< d
Zded< d
S )SeedSummaryLiteral['reset', 'add']moder   r   images_processedgarments_createdghosts_generatedzlist[SeedError]errorsNzResetSummary | Nonereset_summary)	r   r   r   r    r+   r,   r-   r.   r/   r!   r!   r!   r"   r(   7   s   
 r(   dbr	   returnc                   st  |  ttI dH   }|  ttI dH   }t|}t|}|  ttI dH  |  ttI dH  |  tt	tj
tkI dH }t|  }t|}|D ]
}| |I dH  qW|  I dH  d}	ttj}
dD ]6}|
| }| s}qr| D ]&}| r|	tdd |dD 7 }	t| q| r|  |	d7 }	qqrtd||||	 t||||	d	S )
zDelete all garments/faces/non-global users and wipe storage dirs.

    Preserves the unknown user (GLOBAL_USER_ID). Shared by /admin/reset and
    the seed service's reset mode.
    Nr   )	originalsghost_mannequinfacessegmentationc                 s  s    | ]	}|  rd V  qdS )   N)is_file).0fr!   r!   r"   	<genexpr>^   s    z!reset_all_data.<locals>.<genexpr>*r6   z8Reset: %d garments, %d faces, %d users, %d files deleted)r   r   r   r   )executer   r   scalarsallr   lenr   r   whereidr
   listcommitr   r   
UPLOAD_DIRis_diriterdirsumrglobshutilrmtreer7   unlinkloggerinfor   )r0   garmentsr4   
n_garmentsn_facesresultnon_global_usersn_usersur   basesubsub_diritemr!   r!   r"   reset_all_data@   sL    
rY   dirsc                 C  sZ   g }| D ]&}|  std| qt| D ]}| r)|j tv r)|	| qq|S )Nz*Resource directory not found, skipping: %s)
rE   rL   warningsortedrF   r7   suffixlowerIMAGE_EXTENSIONSappend)rZ   pathsdpr!   r!   r"   _collect_imagesq   s   
rd   addgarment_servicer   r*   r)   resource_dirslist[Path] | Noneprogress_cbCallable[[str], None] | Nonec                   s<  |dur|nt }t|d}|dkrt| I dH |_t|}t|}|dkr.|r,|d |S t|dD ]\}	}
d|	 d| d	|
j }|rL|| d
 z|
 }W n! t	ys } z|j
tt|
dt|d W Y d}~q3d}~ww z|j| |ddI dH }W n' ty } ztd|
 |j
tt|
dt|d W Y d}~q3d}~ww | jd7  _|s|j
tt|
ddd q3| jt|7  _|D ]O}|r|| d|j d|j d z|| |jI dH  | jd7  _W q ty } ztd|j |j
tt|
dt|d W Y d}~qd}~ww q3|S )u   Seed preset garment images into the unknown user's wardrobe.

    Each image is analyzed (LLM), saved to DB, and has a ghost mannequin
    generated. Per-image failures are recorded and do not abort the batch.

    Note: `add` mode is not idempotent — rerunning creates duplicates.
    N)r*   resetr   z(No images found in resource directories.r6   [/z] u    — analyzingread)r%   r&   r'   )user_idzanalyze_and_save failed for %sanalyzezLLM returned 0 garmentsu    — ghost ()z$generate_ghost failed for garment %sghost)r   r(   rY   r/   rd   r?   	enumeratename
read_bytesOSErrorr.   r`   r#   r$   analyze_and_save	ExceptionrL   	exceptionr+   r,   category_maincategory_subgenerate_ghostrA   r-   )r0   rf   r*   rg   ri   rZ   summaryra   totalidxpathlabelimage_byteserN   gr!   r!   r"   seed_wardrobe}   sl   
r   )r0   r	   r1   r   )rZ   r   r1   r   )re   NN)r0   r	   rf   r   r*   r)   rg   rh   ri   rj   r1   r(   ))__doc__
__future__r   loggingrI   collections.abcr   pathlibr   typingr   pydanticr   
sqlalchemyr   r   sqlalchemy.ext.asyncior	   
app.configr
   r   app.models.facer   app.models.garmentr   app.models.userr   app.services.garment_servicer   	getLoggerr   rL   r   r    r_   r   r#   r(   rY   rd   r   r!   r!   r!   r"   <module>   s:    

	
1