o
    @TjB$                     @   s   d Z ddl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mZ ddlmZ ddlmZmZmZmZ dd	lmZ dd
lmZmZmZ eeZG dd dZdS )u  Garment analysis pipeline: image save → LLM analysis → DB persist.

Supports two modes via auto_save flag:
- auto_save=True (default): analyze + save to DB in one step (analyze_and_save)
- auto_save=False: analyze only (analyze_only), then client can selectively save (save_garments)

Ghost mannequin generation is a separate step via generate_ghost() (requires DB record)
or generate_ghost_preview() (stateless, before save).
    N)Path)select)AsyncSession)GLOBAL_USER_IDsettings)Garment)BaseLLMProviderGarmentAnalysisStyleAnalysisStyleAnalysisTemp)SegmentationService)resize_image_if_neededsave_ghost_mannequin_imagesave_original_imagec                   @   s0  e Zd ZdedefddZdedefddZd	ed
ej	dB de
ee ef fddZ	d!dedee ded
ej	dB deedB  dB dee fddZded	ed
ej	dB dee fddZ	d!deded
ej	dB dedB def
ddZ	d!dedej	dedB defddZd	edefddZd	edefdd ZdS )"GarmentServicellm_providersegmentation_servicec                 C   s   || _ || _d S N)llmsegmentation)selfr   r    r   </home/ubuntu/htdocs/ootd-api/app/services/garment_service.py__init__&   s   
zGarmentService.__init__ghost_bytesreturnc                    s@   zt | jj|I dH W S  ty   tjddd | Y S w )a  Strip the plain white backdrop from an LLM ghost mannequin output.

        The ghost prompt asks the model for a solid white background because no
        image model can be relied on to emit a true alpha channel (gpt-image-2
        rejects transparent backgrounds outright). rembg runs here to produce
        the transparent PNG that VTON and the wardrobe UI expect. rembg is
        synchronous, so it is offloaded to a worker thread; on failure the raw
        LLM bytes are returned so the caller still gets a usable image.
        Nz?Ghost mannequin background removal failed; using raw LLM outputT)exc_info)asyncio	to_threadr   remove_background	Exceptionloggerwarning)r   r   r   r   r   _strip_ghost_background.   s   
z&GarmentService._strip_ghost_backgroundimage_bytesuser_idNc                    s\   |pt }t|}t||}| j|I dH }|s"td g |fS tdt| ||fS )u   Analyze image without saving to DB.

        1. Resolve user_id (None → global)
        2. Resize & save original image to disk
        3. LLM garment analysis

        Returns (analysis_items, source_image_path).
        NzLLM returned no garment itemszLLM detected %d garment(s))	r   r   r   r   analyze_garmentr!   r"   infolen)r   r$   r%   resolved_user_idresizedsource_pathitemsr   r   r   analyze_onlyC   s   

zGarmentService.analyze_onlydbr,   source_image_pathghost_image_pathsc              
      s   |pt }g }t|D ]+\}}	d}
|r|t|k r|| }
t||	j|	j|	j|	j||
d}|| |	| q|
 I dH  |D ]
}||I dH  q@|S )u`  Save analyzed garment items to DB.

        Args:
            items: LLM analysis results to persist.
            source_image_path: Path to the already-saved source image.
            user_id: Owner (None → global user).
            ghost_image_paths: Optional per-item ghost image paths.

        Returns list of saved Garment ORM objects.
        N)r%   category_maincategory_subdescriptiontagsr/   ghost_image_path)r   	enumerater(   r   r1   r2   r3   r4   addappendcommitrefresh)r   r.   r,   r/   r%   r0   r)   garmentsiitem
ghost_pathgarmentgr   r   r   save_garments\   s,   
	zGarmentService.save_garmentsc                    s6   |  ||I dH \}}|sg S | ||||I dH S )u
  Analysis pipeline (fast path — no ghost mannequin).

        1. Resolve user_id (None → global)
        2. Resize & save original image
        3. LLM garment analysis
        4. Persist garments to DB

        Returns list of saved Garment ORM objects.
        N)r-   rA   )r   r.   r$   r%   r,   r+   r   r   r   analyze_and_save   s
   zGarmentService.analyze_and_saver=   image_modelc              
      s   |pt }ttj| }| std| | }t|dd}z| j	||d|I dH }	W n t
yC }
 ztd|
 |
d}
~
ww |	du rLtd| |	I dH }	t|	|}|S )u&  Generate ghost mannequin without a DB record (stateless preview).

        Reads source image from disk, generates ghost via LLM, saves to disk.
        Returns the ghost image path (relative). ``image_model`` selects the
        image-generation model (``None`` → provider default).
        Source image not found:    max_sizeeditN'   LLM 고스트 마네킹 생성 실패: D   LLM이 고스트 마네킹 이미지를 반환하지 않았습니다)r   r   r   
UPLOAD_DIRexists
ValueError
read_bytesr   r   generate_ghost_mannequinr    RuntimeErrorr#   r   )r   r/   r=   r%   rC   r)   source_fullr$   r*   r   er>   r   r   r   generate_ghost_preview   s(   
z%GarmentService.generate_ghost_preview
garment_idc              
      s>  | tttj|kI dH }| }|du r!td| d|jdur(|S tt	j
|j }| s<td|j | }t|dd}t|j|j|j|jd}	z| j||	d|I dH }
W n tyt } ztd	| |d}~ww |
du r}td
| |
I dH }
t|
|j}||_| I dH  ||I dH  |S )u	  Generate ghost mannequin for an existing garment.

        Reads the source image, calls LLM image generation, saves result,
        and updates the garment record. ``image_model`` selects the
        image-generation model (``None`` → provider default).
        NzGarment z
 not foundrD   rE   rF   )r1   r2   r3   r4   rH   rI   rJ   )executer   r   whereidscalar_one_or_nonerM   r5   r   r   rK   r/   rL   rN   r   r	   r1   r2   r3   r4   r   rO   r    rP   r#   r   r%   r9   r:   )r   r.   rT   rC   resultr?   rQ   r$   r*   r=   r   rR   r>   r   r   r   generate_ghost   sD    
zGarmentService.generate_ghostc                       t |}| j|I dH S )zAnalyze overall outfit style from image.

        1. Resize image for LLM input
        2. Call LLM style analysis

        Returns StyleAnalysis with scores and comments.
        N)r   r   analyze_styler   r$   r*   r   r   r   r\      s   zGarmentService.analyze_stylec                    r[   )z<Context-aware outfit style analysis (time/occasion/weather).N)r   r   analyze_style_tempr]   r   r   r   r^      s   z!GarmentService.analyze_style_tempr   )__name__
__module____qualname__r   r   r   bytesr#   uuidUUIDtuplelistr	   strr-   r   r   rA   rB   rS   rZ   r
   r\   r   r^   r   r   r   r   r   %   sz    


,

&
5r   )__doc__r   loggingrc   pathlibr   
sqlalchemyr   sqlalchemy.ext.asyncior   
app.configr   r   app.models.garmentr   app.services.llm.baser   r	   r
   r   !app.services.segmentation_servicer   app.utils.imager   r   r   	getLoggerr_   r!   r   r   r   r   r   <module>   s    

