
    +j7                     F   d Z ddlZddlmZ ddlmZ  G d d          ZdefdZ e	h d	          Z
 e	h d
          ZdedefdZd ZdedefdZdZdedefdZdedeee         ee         f         fdZdededefdZdededefdZd/dedededefdZdedeeee         f         fdZd ee         d!ed"edee         fd#Zded$ed%ed&edee         f
d'Z	 	 	 	 	 	 d0d$ed%ed&ed*eee                  d+ee         d!ed"ed,ee         d-edeee         ef         fd.ZdS )1zp
Job utilities for the /api/jobs endpoint.
Provides normalization and helper functions for job status tracking.
    N)Optional)
prune_dictc                   4    e Zd ZdZdZdZdZdZdZeeeeegZ	dS )	JobStatuszJob status constants.pendingin_progress	completedfailed	cancelledN)
__name__
__module____qualname____doc__PENDINGIN_PROGRESS	COMPLETEDFAILED	CANCELLEDALL     4/home/wildlama/comfy/ComfyUI/comfy_execution/jobs.pyr   r      s=        GKIFIKFI
>CCCr   r   returnc                     t          | t                    s$t          dt          |           j                   t          t          j        |                     | k    rt          d          | S )u  Validate a client-supplied job (prompt) id.

    Job ids must be UUIDs in the canonical lowercase hyphenated form. The id
    is stored and compared verbatim everywhere downstream — history keys,
    websocket events, and /interrupt matching — so accepting another spelling
    would silently rewrite the client's id and then miss every exact-match
    lookup. Rejecting loudly beats that.

    Returns the id unchanged. Raises ValueError when the value is not a
    string in canonical UUID form.
    zjob id must be a string, got z<job id must be a UUID in canonical lowercase hyphenated form)
isinstancestr
ValueErrortyper   uuidUUIDvalues    r   validate_job_idr#      sh     eS!! QOe9MOOPPP
49U%%WXXXLr   >   3dtextaudiovideoimages>   .fbx.glb.obj.gltf.usdzfilenamec                 l    |                                  t          fdt          D                       S )Nc              3   B   K   | ]}                     |          V  d S Nendswith).0extlowers     r   	<genexpr>z#has_3d_extension.<locals>.<genexpr>3   s/      AAsu~~c""AAAAAAr   )r6   anyTHREE_D_EXTENSIONS)r.   r6   s    @r   has_3d_extensionr:   1   s6    NNEAAAA.@AAAAAAr   c                     | dS t          | t                    rt          |           r| ddddS dS t          | t                    r| S dS )zNormalize a single output list item for the jobs API.

    Returns the normalized item, or None to exclude it.
    String items with 3D extensions become {filename, type, subfolder} dicts.
    Noutput r$   )r.   r   	subfolder	mediaType)r   r   r:   dict)items    r   normalize_output_itemrB   6   se     |t$ D!! 	\ $hRVZ[[[t$ 4r   outputsc                 f   i }|                                  D ]\  }}t          |t                    s|||<    i }|                                 D ]]\  }}|dk    st          |t                    s|||<   &g }|D ]-}|t	          |          }	|                    |	|	n|           .|||<   ^|||<   |S )zNormalize raw node outputs for the jobs API.

    Transforms string 3D filenames into file output dicts and removes
    None items. All other items (non-3D strings, dicts, etc.) are
    preserved as-is.
    animated)itemsr   r@   listrB   append)
rC   
normalizednode_idnode_outputsnormalized_node
media_typerF   normalized_itemsrA   norms
             r   normalize_outputsrP   G   s     J!( . .,-- 	".Jw!-!3!3!5!5 
	; 
	;JZ''z%/F/F'.3
+! L L<,T22 ''0@dKKKK*:OJ''-
7r   i   r"   c                 ^    t          |           t          k    rd| iS | dt                   ddS )zCreate a text preview dict with optional truncation.

    Returns:
        dict with 'content' and optionally 'truncated' flag
    contentNT)rR   	truncated)lenTEXT_PREVIEW_MAX_LENGTHr!   s    r   _create_text_previewrV   f   sB     5zz,,,5!!1112  r   
extra_datac                     |                      d          }|                      di           }|                     di                                d          }||fS )zqExtract create_time and workflow_id from extra_data.

    Returns:
        tuple: (create_time, workflow_id)
    create_timeextra_pnginfoworkflowidget)rW   rY   rZ   workflow_ids       r   _extract_job_metadatar`   t   sV     ..//KNN?B77M##J3377==K##r   rM   rA   c                 :   | t           v rdS |                    dd          }|r,|                    d          s|                    d          rdS |                    dd                                          t	          fdt
          D                       rdS dS )	au  
    Check if an output item is previewable.
    Matches frontend logic in ComfyUI_frontend/src/stores/queueStore.ts
    Maintains backwards compatibility with existing logic.

    Priority:
    1. media_type is 'images', 'video', 'audio', or '3d'
    2. format field starts with 'video/' or 'audio/'
    3. filename has a 3D extension (.obj, .fbx, .gltf, .glb, .usdz)
    Tformatr=   zvideo/zaudio/r.   c              3   B   K   | ]}                     |          V  d S r1   r2   )r4   r5   r.   s     r   r7   z!is_previewable.<locals>.<genexpr>   s1      
@
@c8S!!
@
@
@
@
@
@r   F)PREVIEWABLE_MEDIA_TYPESr^   
startswithr6   r8   r9   )rM   rA   fmtr.   s      @r   is_previewablerg      s     ,,,t ((8R
 
 C
 x(( CNN8,D,D t xx
B''--//H

@
@
@
@-?
@
@
@@@ t5r   statusc           	      b    | \  }}}}}t          |          \  }}t          ||||d|d          S )zvConvert queue item tuple to unified job dict.

    Expects item with sensitive data already removed (5 elements).
    r   )r\   rh   priorityrY   outputs_countr_   )r`   r   )rA   rh   rj   	prompt_id_rW   rY   r_   s           r   normalize_queue_itemrn      sT    
 -1)HiJ4Z@@K""    r   Frl   history_iteminclude_outputsc                 l   |d         }|\  }}}}}t          |          \  }}	|                    di           }
|
r|
                    d          nd}|                    di           }t          |          \  }}d}d}d}d}|
r|
                    dg           }|D ]}t          |t          t
          f          r~t          |          dk    rk|d	         |d
         }}t          |t                    rF|dk    r|                    d          }r|dv r&|                    d          }|dk    r|}|dk    rd}|dk    rt          j	        }n-|dk    r|rt          j
        nt          j        }nt          j	        }t          | |||||||||	d
          }|rt          |          |d<   |
|d<   ||d|d<   |S )zConvert history item dict to unified job dict.

    History items have sensitive data already removed (prompt tuple has 5 elements).
    promptrh   
status_strNrC   Fmessages   r      execution_start	timestamp)execution_successexecution_errorexecution_interruptedrz   r{   Tsuccesserror)
r\   rh   rj   rY   execution_start_timeexecution_end_timerz   rk   preview_outputr_   execution_status)rr   rW   r[   )r`   r^   get_outputs_summaryr   rG   tuplerT   r@   r   r   r   r   r   rP   )rl   ro   rp   prompt_tuplerj   rm   rr   rW   rY   r_   status_infors   rC   rk   r   rz   r~   r   was_interruptedrt   entry
event_name
event_datarh   jobs                            r   normalize_history_itemr      s+   
  )L)5&HaQ4Z@@K""8R00K2=G...4Jy"--G$7$@$@!M>OO 3??:r22 	3 	3E%$// 
3CJJ!OO).q58J
j$// 3!%666/9~~k/J/J,,#'hhh-7^^K-H-H*%):::.8OO'+BBB.2OY$	w		(7M$$Y=M$
" 40*&("   C  
*733I"-$
 
J
 Jr   c                    d}d}d}|                                  D ]#\  }}t          |t                    s|                                 D ]\  }}|dk    st          |t                    s!|D ]}t          |t                    snt	          |          }	|	[|dk    rT|dz  }|Mt          |t
                    r|r|d         nd}
nt          |          }
t          |
          }i |||d}||}|	}|dz  }|t          ||          r1i |d|i}d	|vr||d	<   |	                    d
          dk    r|}||}ό%||p|fS )z
    Count outputs and find preview in a single pass.
    Returns (outputs_count, preview_output).

    Preview priority (matching frontend):
    1. type="output" with previewable media
    2. Any previewable media
    r   NrE   r%   rv   r=   )nodeIdr?   r   r?   r   r<   )
rF   r   r@   rG   rB   r   r   rV   rg   r^   )rC   countr   fallback_previewrJ   rK   rM   rF   rA   rI   
text_valuetext_previewenricheds                r   r   r      s    EN!( 04 04,-- 	!-!3!3!5!5 -	4 -	4JZ''z%/F/F' (4 (4!$-- &!6t!<!<J!)%//!QJE-5#-dE#:#: !;<@1HabJJ14TJ/CJ/O/O,"&2,".51;," ," ,"
 $4#;7?$4 %D
!-!*d33 
4   '   H #$..0:-xx''833)1)1+3(Q(4-	4^ .4$444r   jobssort_by
sort_orderc                 L    |dk    }|dk    rd }nd }t          | ||          S )z,Sort jobs list by specified field and order.descexecution_durationc                 p    |                      dd          }|                      dd          }|r|r||z
  ndS )Nr~   r   r   r]   )r   startends      r   get_sort_keyz#apply_sorting.<locals>.get_sort_key6  sB    GG2A66E''.22C"%6%63;;Q6r   c                 .    |                      dd          S )NrY   r   r]   )r   s    r   r   z#apply_sorting.<locals>.get_sort_key;  s    77=!,,,r   )keyreverse)sorted)r   r   r   r   r   s        r   apply_sortingr   1  sR    V#G&&&	7 	7 	7 	7
	- 	- 	- $L'::::r   runningqueuedhistoryc                     | |v rt          | ||          d          S |D ]*}|d         | k    rt          |t          j                  c S +|D ]*}|d         | k    rt          |t          j                  c S +dS )aY  
    Get a single job by prompt_id from history or queue.

    Args:
        prompt_id: The prompt ID to look up
        running: List of currently running queue items
        queued: List of pending queue items
        history: Dict of history items keyed by prompt_id

    Returns:
        Job dict with full details, or None if not found
    T)rp   rv   N)r   rn   r   r   r   )rl   r   r   r   rA   s        r   get_jobr   A  s     G%i1CUYZZZZ E E7i'i.CDDDDD    A A7i'i.?@@@@@   4r   
created_atr   status_filterr_   limitoffsetc	                    g }	|t           j        }t           j        |v r2| D ]/}
|	                    t	          |
t           j                             0t           j        |v r2|D ]/}
|	                    t	          |
t           j                             0t           j        t           j        t           j        h}|t          |          z  }|rV|
                                D ]A\  }}t          ||          }|                    d          |v r|	                    |           Brfd|	D             }	t          |	||          }	t          |	          }|dk    r
|	|d         }	|
|	d|         }	|	|fS )ae  
    Get all jobs (running, pending, completed) with filtering and sorting.

    Args:
        running: List of currently running queue items
        queued: List of pending queue items
        history: Dict of history items keyed by prompt_id
        status_filter: List of statuses to include (from JobStatus.ALL)
        workflow_id: Filter by workflow ID
        sort_by: Field to sort by ('created_at', 'execution_duration')
        sort_order: 'asc' or 'desc'
        limit: Maximum number of items to return
        offset: Number of items to skip

    Returns:
        tuple: (jobs_list, total_count)
    Nrh   c                 F    g | ]}|                     d           k    |S )r_   r]   )r4   jr_   s     r   
<listcomp>z get_all_jobs.<locals>.<listcomp>  s/    GGGa155#7#7;#F#F#F#F#Fr   r   )r   r   r   rH   rn   r   r   r   r   setrF   r   r^   r   rT   )r   r   r   r   r_   r   r   r   r   r   rA   history_statusesrequested_history_statusesrl   ro   r   total_counts       `            r   get_all_jobsr   \  s   8 D!-- 	K 	KDKK,T93HIIJJJJM)) 	G 	GDKK,T93DEEFFFF!+Y-=y?RS!1C4F4F!F! !'.}} 	! 	!#I|(LAACwwx  $>>>C    HGGGG4GGGw
33Dd))KzzFGG}FUF|+r   )F)NNr   r   Nr   )r   r   typingr   comfy_api.internalr   r   r   r#   	frozensetrd   r9   boolr:   rB   r@   rP   rU   rV   r   intr`   rg   rn   r   r   rG   r   r   r   r   r   r   <module>r      sN   
        ) ) ) ) ) )? ? ? ? ? ? ? ?c    ( $)$N$N$NOO  YIIIJJ Bs Bt B B B B
  "t     8       	$d 	$uXc]HSM5Q/R 	$ 	$ 	$ 	$s $ 4    8u c d    $> >c > >PT >ae > > > >B?5 ?5%Xd^0C*D ?5 ?5 ?5 ?5D;T
 ;S ;c ;d4j ; ; ; ; s T 4 $ 8TX>    > *.!%= === = DI&	=
 #= = = C== = 4:s?= = = = = =r   