
    WiR#                     v    d dl Zd dlmZ d dlmZ d dlmZmZm	Z	m
Z
mZ d dlmZ d dlmZmZ dZ G d d	e      Zy)
    N)Document)
csr_matrix)CallableMappingListTupleUnion)BaseRepresentation)truncate_document%validate_truncate_document_parametersz;What are these documents about? Please give a single label.c                       e Zd ZdZ	 	 	 	 	 	 ddedz  dededz  dedz  deeef   dz  f
dZ	d	e
j                  d
edeeeeeef      f   deeeeeef      f   fdZy)	LangChaina  Using chains in langchain to generate topic labels.

    The classic example uses `langchain.chains.question_answering.load_qa_chain`.
    This returns a chain that takes a list of documents and a question as input.

    You can also use Runnables such as those composed using the LangChain Expression Language.

    Arguments:
        chain: The langchain chain or Runnable with a `batch` method.
               Input keys must be `input_documents` and `question`.
               Output key must be `output_text`.
        prompt: The prompt to be used in the model. If no prompt is given,
                `self.default_prompt_` is used instead.
                 NOTE: Use `"[KEYWORDS]"` in the prompt
                 to decide where the keywords need to be
                 inserted. Keywords won't be included unless
                 indicated. Unlike other representation models,
                 Langchain does not use the `"[DOCUMENTS]"` tag
                 to insert documents into the prompt. The load_qa_chain function
                 formats the representative documents within the prompt.
        nr_docs: The number of documents to pass to LangChain
        diversity: The diversity of documents to pass to LangChain.
                   Accepts values between 0 and 1. A higher
                   values results in passing more diverse documents
                   whereas lower values passes more similar documents.
        doc_length: The maximum length of each document. If a document is longer,
                    it will be truncated. If None, the entire document is passed.
        tokenizer: The tokenizer used to calculate to split the document into segments
                   used to count the length of a document.
                       * If tokenizer is 'char', then the document is split up
                         into characters which are counted to adhere to `doc_length`
                       * If tokenizer is 'whitespace', the document is split up
                         into words separated by whitespaces. These words are counted
                         and truncated depending on `doc_length`
                       * If tokenizer is 'vectorizer', then the internal CountVectorizer
                         is used to tokenize the document. These tokens are counted
                         and truncated depending on `doc_length`. They are decoded with
                         whitespaces.
                       * If tokenizer is a callable, then that callable is used to tokenize
                         the document. These tokens are counted and truncated depending
                         on `doc_length`
        chain_config: The configuration for the langchain chain. Can be used to set options
                      like max_concurrency to avoid rate limiting errors.
    Usage:

    To use this, you will need to install the langchain package first.
    Additionally, you will need an underlying LLM to support langchain,
    like openai:

    `pip install langchain`
    `pip install openai`

    Then, you can create your chain as follows:

    ```python
    from langchain.chains.question_answering import load_qa_chain
    from langchain.llms import OpenAI
    chain = load_qa_chain(OpenAI(temperature=0, openai_api_key=my_openai_api_key), chain_type="stuff")
    ```

    Finally, you can pass the chain to BERTopic as follows:

    ```python
    from bertopic.representation import LangChain

    # Create your representation model
    representation_model = LangChain(chain)

    # Use the representation model in BERTopic on top of the default pipeline
    topic_model = BERTopic(representation_model=representation_model)
    ```

    You can also use a custom prompt:

    ```python
    prompt = "What are these documents about? Please give a single label."
    representation_model = LangChain(chain, prompt=prompt)
    ```

    You can also use a Runnable instead of a chain.
    The example below uses the LangChain Expression Language:

    ```python
    from bertopic.representation import LangChain
    from langchain.chains.question_answering import load_qa_chain
    from langchain.chat_models import ChatAnthropic
    from langchain.schema.document import Document
    from langchain.schema.runnable import RunnablePassthrough
    from langchain_experimental.data_anonymizer.presidio import PresidioReversibleAnonymizer

    prompt = ...
    llm = ...

    # We will construct a special privacy-preserving chain using Microsoft Presidio

    pii_handler = PresidioReversibleAnonymizer(analyzed_fields=["PERSON"])

    chain = (
        {
            "input_documents": (
                lambda inp: [
                    Document(
                        page_content=pii_handler.anonymize(
                            d.page_content,
                            language="en",
                        ),
                    )
                    for d in inp["input_documents"]
                ]
            ),
            "question": RunnablePassthrough(),
        }
        | load_qa_chain(representation_llm, chain_type="stuff")
        | (lambda output: {"output_text": pii_handler.deanonymize(output["output_text"])})
    )

    representation_model = LangChain(chain, prompt=representation_prompt)
    ```
    Npromptnr_docs	diversity
doc_length	tokenizerc                     || _         ||nt        | _        t        | _        || _        || _        || _        || _        || _        t        | j                  | j                         y )N)
chainDEFAULT_PROMPTr   default_prompt_chain_configr   r   r   r   r   )selfr   r   r   r   r   r   r   s           n/home/sietch6/trending-topics-pipeline/venv/lib/python3.12/site-packages/bertopic/representation/_langchain.py__init__zLangChain.__init__   sW     
 & 2f-("$"-dnndooN    	documentsc_tf_idftopicsreturnc                    |j                  |||d| j                  | j                        \  }}}}|j                         D cg c]<  }|D cg c].  }t	        t        || j                  | j                  |            0 c}> }	}}d| j                  v r{g }
|D ]R  }t        t        ||          }| j                  j                  ddj                  |            }|
j                  |       T t        |	|
      D cg c]
  \  }}||d }}}n|	D cg c]  }|| j                  d }}| j                  j                  || j                         }|D cg c]  }|d   j#                          }}t        |j%                         |      D ci c]%  \  }}||d	fgt'        d
      D cg c]  }d c}z   ' }}}}|S c c}w c c}}w c c}}w c c}w c c}w c c}w c c}}}w )aJ  Extract topics.

        Arguments:
            topic_model: A BERTopic model
            documents: All input documents
            c_tf_idf: The topic c-TF-IDF representation
            topics: The candidate topics as calculated with c-TF-IDF

        Returns:
            updated_topics: Updated topic representations
        i  )r   r   r   
nr_samplesnr_repr_docsr   )page_contentz
[KEYWORDS]z, )input_documentsquestion)inputsconfigoutput_text   	   ) r   )_extract_representative_docsr   r   valuesr   r   r   r   r   nextzipreplacejoinappendr   batchr   stripkeysrange)r   topic_modelr   r   r   repr_docs_mappings_docsdoc
chain_docspromptstopickeywordsr   r'   outputsoutputlabelslabelupdated_topicss                       r   extract_topicszLangChain.extract_topics   s	   & '2&N&Nnn 'O '
#Aq! +113,

    &7T__VZVdVdfi&jk,

 ,
 4;;&G 'VE] 34,,\499X;NOv&'
 Y\\fhoXpqf$FCqFq V``T$DKKH`F` **""&9J9J"K>EFF&'--/FF SVVhVmVmVoqwRx
 
BN%EUAJ<E!H"=q7"===
 
 =,
" r a
 G #>
sB   	G3G G>GGGG",	G5G"GG")N   NNNN)__name__
__module____qualname____doc__strintfloatr	   r   r   pd	DataFramer   r   r   r   rF    r   r   r   r      s    vv ""&!%15O d
O 	O
 4<O $JO h'$.O(< <<< 	<
 T%U
"3445< 
d5c?++	,<r   r   )pandasrO   langchain.docstore.documentr   scipy.sparser   typingr   r   r   r   r	   bertopic.representation._baser
   bertopic.representation._utilsr   r   r   r   rQ   r   r   <module>rX      s.     0 # 8 8 < cNI" Ir   