a
    Ad:                     @   s   d dl Z d dlmZ d dlZd dlmZmZmZ d dlm	Z	 G dd dZ
eddd	gZG d
d dejjZG dd deZG dd deZdS )    N)
namedtuple)prompt_parserdevices	sd_hijack)optsc                   @   s   e Zd ZdZdd ZdS )PromptChunkan  
    This object contains token ids, weight (multipliers:1.4) and textual inversion embedding info for a chunk of prompt.
    If a prompt is short, it is represented by one PromptChunk, otherwise, multiple are necessary.
    Each PromptChunk contains an exact amount of tokens - 77, which includes one for start and end token,
    so just 75 tokens from prompt.
    c                 C   s   g | _ g | _g | _d S N)tokensmultipliersfixes)self r   >/var/www/html/stable-diffusion-webui/modules/sd_hijack_clip.py__init__   s    zPromptChunk.__init__N)__name__
__module____qualname____doc__r   r   r   r   r   r   
   s   r   PromptChunkFixoffset	embeddingc                       sh   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Z  ZS )%FrozenCLIPEmbedderWithCustomWordsBasezA pytorch module that is a wrapper for FrozenCLIPEmbedder module. it enhances FrozenCLIPEmbedder, making it possible to
    have unlimited prompt length and assign weights to tokens in prompt.
    c                    sB   t    || _|| _d| _t|dd| _t|dd| _d | _d S )NK   is_trainableF	input_keytxt)	superr   wrappedhijackchunk_lengthgetattrr   r   legacy_ucg_valr   r   r   	__class__r   r   r   #   s    
z.FrozenCLIPEmbedderWithCustomWordsBase.__init__c                 C   s8   t  }| jg| jg| jd   |_dg| jd  |_|S )z+creates an empty PromptChunk and returns it         ?   )r   id_startid_endr   r	   r
   )r   chunkr   r   r   empty_chunk1   s    z1FrozenCLIPEmbedderWithCustomWordsBase.empty_chunkc                 C   s   t t|d| j | j S )zreturns the maximum number of tokens a prompt of a known length can have before it requires one more PromptChunk to be representedr%   )mathceilmaxr   )r   token_countr   r   r   get_target_prompt_token_count9   s    zCFrozenCLIPEmbedderWithCustomWordsBase.get_target_prompt_token_countc                 C   s   t dS )z3Converts a batch of texts into a batch of token idsNNotImplementedError)r   textsr   r   r   tokenize>   s    z.FrozenCLIPEmbedderWithCustomWordsBase.tokenizec                 C   s   t dS )a  
        converts a batch of token ids (in python lists) into a single tensor with numeric respresentation of those tokens;
        All python lists with tokens are assumed to have same length, usually 77.
        if input is a list with B elements and each element has T tokens, expected output shape is (B, T, C), where C depends on
        model - can be 768 and 1024.
        Among other things, this call will read self.hijack.fixes, apply it to its inputs, and clear it (setting it to None).
        Nr1   )r   r	   r   r   r   encode_with_transformersC   s    	z>FrozenCLIPEmbedderWithCustomWordsBase.encode_with_transformersc                 C   s   t dS )a  Converts text into a tensor with this text's tokens' embeddings. Note that those are embeddings before they are passed through
        transformers. nvpt is used as a maximum length in tokens. If text produces less teokens than nvpt, only this many is returned.Nr1   )r   	init_textnvptr   r   r   encode_embedding_init_textN   s    z@FrozenCLIPEmbedderWithCustomWordsBase.encode_embedding_init_textc                    s4  t jrt|}n
|dgg}dd |D }g t  ddd fdd	}t||D ]\}\}}|d	kr|dkr|  qbd}|t|k rb|| }	|	jkrt j	nt j
dkrJt j	jkrJdkrJt j	 t j
krJd
 }
 j	|
d } j|
d } j	d|
  _	 jd|
  _|  | _	| _t j	jkrb|  jj||\}}|du r j	|	  j| |d
7 }qt|j}t j	| jkr|   jtt j	|   j	dg| 7  _	  j|g| 7  _||7 }qqb j	s"s,|dd fS )z
        this transforms a single prompt into a list of PromptChunk objects - as many as needed to
        represent the prompt.
        Returns the list and the total number of tokens in the prompt.
        r&   c                 S   s   g | ]\}}|qS r   r   ).0text_r   r   r   
<listcomp>`       zGFrozenCLIPEmbedderWithCustomWordsBase.tokenize_line.<locals>.<listcomp>r   Fc                    s   | rt  j7 n
j7 jt  j }|dkr`  jjg| 7  _  jdg| 7  _jg j jg  _dg j dg  _d  t  dS )zputs current chunk into the list of results and produces the next one - empty;
            if is_last is true, tokens <end-of-text> tokens at the end won't add to token_countr   r&   r>   N)lenr	   r   r)   r
   r(   appendr   )is_lastto_addr*   chunks
last_commar   r/   r   r   
next_chunkg   s    

zGFrozenCLIPEmbedderWithCustomWordsBase.tokenize_line.<locals>.next_chunkBREAKr%   NT)rA   )F)r   enable_emphasisr   parse_prompt_attentionr4   r   zipr?   comma_tokenr	   comma_padding_backtrackr   r
   r   embedding_dbfind_embedding_at_positionr@   intvectorsr   r   )r   lineparsed	tokenizedrF   r	   r:   weightpositiontokenZbreak_locationZreloc_tokensZreloc_multsr   Zembedding_length_in_tokensemb_lenr   rC   r   tokenize_lineT   sZ    

>


z3FrozenCLIPEmbedderWithCustomWordsBase.tokenize_linec                 C   sZ   d}i }g }|D ]@}||v r&|| }n |  |\}}t||}|||< || q||fS )z
        Accepts a list of texts and calls tokenize_line() on each, with cache. Returns the list of results and maximum
        length, in tokens, of all texts.
        r   )rX   r.   r@   )r   r3   r/   cachebatch_chunksrQ   rD   Zcurrent_token_countr   r   r   process_texts   s    

z3FrozenCLIPEmbedderWithCustomWordsBase.process_textsc                    s  t jrddl}|j|S |\}}i }tdd |D }g }t|D ]  fdd|D }dd |D }	dd |D }
dd |D j_	jj	D ]}|D ]\}}|||j
< qq|	|
}|| qLt jrd|rdg }| D ]<\}}|j}|sq|d	d
dd
}|| d|  q|rdjjdrR|jjd d|jjd< tjddrt||d jfS t|S dS )ac  
        Accepts an array of texts; Passes texts through transformers network to create a tensor with numerical representation of those texts.
        Returns a tensor with shape of (B, T, C), where B is length of the array; T is length, in tokens, of texts (including padding) - T will
        be a multiple of 77; and C is dimensionality of each token - for SD1 it's 768, for SD2 it's 1024, and for SDXL it's 1280.
        An example shape returned by this function can be: (2, 77, 768).
        For SDXL, instead of returning one tensor avobe, it returns a tuple with two: the other one with shape (B, 1280) with pooled values.
        Webui usually sends just one text at a time through this function - the only time when texts is an array with more than one elemenet
        is when you do prompt editing: "a picture of a [cat:dog:0.4] eating ice cream"
        r   Nc                 S   s   g | ]}t |qS r   )r?   r9   xr   r   r   r<      r=   zAFrozenCLIPEmbedderWithCustomWordsBase.forward.<locals>.<listcomp>c                    s(   g | ] } t |k r|  n qS r   )r?   r+   )r9   rD   ir   r   r   r<      r=   c                 S   s   g | ]
}|j qS r   )r	   r\   r   r   r   r<      r=   c                 S   s   g | ]
}|j qS r   )r
   r\   r   r   r   r<      r=   c                 S   s   g | ]
}|j qS r   )r   r\   r   r   r   r<      r=   : ,z: z	TI hashesz, return_pooledF)r   use_old_emphasis_implementationZmodules.sd_hijack_clip_oldZsd_hijack_clip_oldZforward_oldr[   r.   ranger   r   nameprocess_tokensr@   (textual_inversion_add_hashes_to_infotextitems	shorthashreplaceextra_generation_paramsgetjoinr    r   torchhstackpooled)r   r3   modulesrZ   r/   Zused_embeddingsZchunk_countzsZbatch_chunkr	   r
   r   	_positionr   zhashesrf   rj   r   r^   r   forward   s@    z-FrozenCLIPEmbedderWithCustomWordsBase.forwardc           
      C   s   t |tj}| j| jkr\tt|D ]0}|| 	| j}| j|||d |j
d f< q*| |}t|dd}t |tj}| }|||j
d |j
 }| }	|||	  }|dur||_|S )a  
        sends one single prompt chunk to be encoded by transformers neural network.
        remade_batch_tokens is a batch of tokens - a list, where every element is a list of tokens; usually
        there are exactly 77 tokens in the list. batch_multipliers is the same but for multipliers instead of tokens.
        Multipliers are used to give more or less weight to the outputs of transformers network. Each multiplier
        corresponds to one token.
        r%   rq   N)r%   )ro   asarraytor   devicer)   id_padre   r?   indexshaper5   r    meanreshapeexpandrq   )
r   Zremade_batch_tokensZbatch_multipliersr	   Z	batch_posr|   ru   rq   Zoriginal_meanZnew_meanr   r   r   rg     s    
z4FrozenCLIPEmbedderWithCustomWordsBase.process_tokens)r   r   r   r   r   r+   r0   r4   r5   r8   rX   r[   rw   rg   __classcell__r   r   r#   r   r      s   _7r   c                       s4   e Zd Z fddZdd Zdd Zdd Z  ZS )	!FrozenCLIPEmbedderWithCustomWordsc           	         s   t  || |j| _| j }|dd | _i | _dd | D }|D ]h\}}d}|D ]D}|dkrn|d }|dkr~|d9 }|dkr|d9 }|d	krZ|d }qZ|dkrJ|| j|< qJ| jjj	| _
| jjj| _| j| _d S )
Nz,</w>c                 S   s8   g | ]0\}}d |v s,d|v s,d|v s,d|v r||fqS )()[]r   )r9   kvr   r   r   r<   ,  r=   z>FrozenCLIPEmbedderWithCustomWords.__init__.<locals>.<listcomp>r&   r   g?r   r   r   )r   r   	tokenizer	get_vocabrm   rK   Ztoken_multsri   r   bos_token_idr(   eos_token_idr)   r{   )	r   r   r   vocabZtokens_with_parensr:   identmultcr#   r   r   r   #  s,    

z*FrozenCLIPEmbedderWithCustomWords.__init__c                 C   s   | j j|dddd }|S )NF)
truncationadd_special_tokens	input_ids)r   r   )r   r3   rS   r   r   r   r4   @  s    z*FrozenCLIPEmbedderWithCustomWords.tokenizec                 C   sH   | j j|tj d}tjdkr>|jtj  }| j jj|}n|j}|S )Nr   output_hidden_statesr%   )r   transformerr   CLIP_stop_at_last_layershidden_states
text_modelfinal_layer_normlast_hidden_stater   r	   outputsru   r   r   r   r5   E  s    
z:FrozenCLIPEmbedderWithCustomWords.encode_with_transformersc                 C   sH   | j jjj}| j j||dddd }|j ||jj jj	d}|S )NptF)
max_lengthreturn_tensorsr   r   r   )
r   r   r   
embeddingsr   token_embeddingry   rT   rz   squeeze)r   r6   r7   Zembedding_layeridsembeddedr   r   r   r8   P  s     z<FrozenCLIPEmbedderWithCustomWords.encode_embedding_init_text)r   r   r   r   r4   r5   r8   r   r   r   r#   r   r   "  s   r   c                       s$   e Zd Z fddZdd Z  ZS )(FrozenCLIPEmbedderForSDXLWithCustomWordsc                    s   t  || d S r   )r   r   r"   r#   r   r   r   Y  s    z1FrozenCLIPEmbedderForSDXLWithCustomWords.__init__c                 C   s>   | j j|| j jdkd}| j jdkr,|j}n|j| j j }|S )Nhiddenr   last)r   r   layerr   r   	layer_idxr   r   r   r   r5   \  s
    zAFrozenCLIPEmbedderForSDXLWithCustomWords.encode_with_transformers)r   r   r   r   r5   r   r   r   r#   r   r   X  s   r   )r,   collectionsr   ro   rr   r   r   r   modules.sharedr   r   r   nnModuler   r   r   r   r   r   r   <module>   s     6