a
    bgx?                     @   s   d Z ddlZddlmZmZmZmZ ddlZddlZddl	m
Z
 ddlmZmZmZmZmZ edddZG d	d
 d
eZG dd deZdS )aa  Utility for using SearxNG meta search API.

SearxNG is a privacy-friendly free metasearch engine that aggregates results from
`multiple search engines
<https://docs.searxng.org/admin/engines/configured_engines.html>`_ and databases and
supports the `OpenSearch
<https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md>`_
specification.

More details on the installation instructions `here. <../../integrations/searx.html>`_

For the search API refer to https://docs.searxng.org/dev/search_api.html

Quick Start
-----------


In order to use this utility you need to provide the searx host. This can be done
by passing the named parameter :attr:`searx_host <SearxSearchWrapper.searx_host>`
or exporting the environment variable SEARX_HOST.
Note: this is the only required parameter.

Then create a searx search instance like this:

    .. code-block:: python

        from langchain_community.utilities import SearxSearchWrapper

        # when the host starts with `http` SSL is disabled and the connection
        # is assumed to be on a private network
        searx_host='http://self.hosted'

        search = SearxSearchWrapper(searx_host=searx_host)


You can now use the ``search`` instance to query the searx API.

Searching
---------

Use the :meth:`run() <SearxSearchWrapper.run>` and
:meth:`results() <SearxSearchWrapper.results>` methods to query the searx API.
Other methods are available for convenience.

:class:`SearxResults` is a convenience wrapper around the raw json result.

Example usage of the ``run`` method to make a search:

    .. code-block:: python

        s.run(query="what is the best search engine?")

Engine Parameters
-----------------

You can pass any `accepted searx search API
<https://docs.searxng.org/dev/search_api.html>`_ parameters to the
:py:class:`SearxSearchWrapper` instance.

In the following example we are using the
:attr:`engines <SearxSearchWrapper.engines>` and the ``language`` parameters:

    .. code-block:: python

        # assuming the searx host is set as above or exported as an env variable
        s = SearxSearchWrapper(engines=['google', 'bing'],
                            language='es')

Search Tips
-----------

Searx offers a special
`search syntax <https://docs.searxng.org/user/index.html#search-syntax>`_
that can also be used instead of passing engine parameters.

For example the following query:

    .. code-block:: python

        s = SearxSearchWrapper("langchain library", engines=['github'])

        # can also be written as:
        s = SearxSearchWrapper("langchain library !github")
        # or even:
        s = SearxSearchWrapper("langchain library !gh")


In some situations you might want to pass an extra string to the search query.
For example when the `run()` method is called by an agent. The search suffix can
also be used as a way to pass extra parameters to searx or the underlying search
engines.

    .. code-block:: python

        # select the github engine and pass the search suffix
        s = SearchWrapper("langchain library", query_suffix="!gh")


        s = SearchWrapper("langchain library")
        # select github the conventional google search syntax
        s.run("large language models", query_suffix="site:github.com")


*NOTE*: A search suffix can be defined on both the instance and the method level.
The resulting query will be the concatenation of the two with the former taking
precedence.


See `SearxNG Configured Engines
<https://docs.searxng.org/admin/engines/configured_engines.html>`_ and
`SearxNG Search Syntax <https://docs.searxng.org/user/index.html#id1>`_
for more details.

Notes
-----
This wrapper is based on the SearxNG fork https://github.com/searxng/searxng which is
better maintained than the original Searx project and offers more features.

Public searxNG instances often use a rate limiter for API usage, so you might want to
use a self hosted instance and disable the rate limiter.

If you are self-hosting an instance you can customize the rate limiter for your
own network as described
`here <https://docs.searxng.org/src/searx.botdetection.html#limiter-src>`_.


For a list of public SearxNG instances see https://searx.space/
    N)AnyDictListOptional)get_from_dict_or_env)	BaseModel
ConfigDictFieldPrivateAttrmodel_validatorreturnc                   C   s
   dddS )Nenjson)languageformat r   r   r   x/var/www/html/cobodadashboardai.evdpl.com/venv/lib/python3.9/site-packages/langchain_community/utilities/searx_search.py_get_default_params   s    r   c                       sf   e Zd ZU dZdZeed< ed fddZeddd	Ze	e
dd
dZe	e
dddZ  ZS )SearxResultsz,Dict like wrapper around search api results. _data)datac                    s    t |}t | | | _dS )zATake a raw result from Searx and make it into a dict like object.N)r   loadssuper__init____dict__)selfr   Z	json_data	__class__r   r   r      s    
zSearxResults.__init__r   c                 C   s   | j S )z$Text representation of searx result.)r   r   r   r   r   __str__   s    zSearxResults.__str__c                 C   s
   |  dS )zGSilence mypy for accessing this field.

        :meta private:
        resultsgetr    r   r   r   r"      s    zSearxResults.resultsc                 C   s
   |  dS )z#Helper accessor on the json result.answersr#   r    r   r   r   r%      s    zSearxResults.answers)__name__
__module____qualname____doc__r   str__annotations__r   r!   propertyr   r"   r%   __classcell__r   r   r   r   r      s   
r   c                	   @   s  e Zd ZU dZe Zeed< dZe	ed< dZ
eed< eedZeed< d	Zee ed
< g Zeee	  ed< g Zeee	  ed< dZee	 ed< dZeed< d	Zee ed< eddeeedddZeddZeedddZ eedddZ!d)e	eee	  eee	  ee	 ee	dddZ"d*e	eee	  ee	 ee	d d!d"Z#d+e	eeee	  eee	  ee	 eee d#d$d%Z$d,e	eeee	  ee	 eee d&d'd(Z%d	S )-SearxSearchWrappera  Wrapper for Searx API.

    To use you need to provide the searx host by passing the named parameter
    ``searx_host`` or exporting the environment variable ``SEARX_HOST``.

    In some situations you might want to disable SSL verification, for example
    if you are running searx locally. You can do this by passing the named parameter
    ``unsecure``. You can also pass the host url scheme as ``http`` to disable SSL.

    Example:
        .. code-block:: python

            from langchain_community.utilities import SearxSearchWrapper
            searx = SearxSearchWrapper(searx_host="http://localhost:8888")

    Example with SSL disabled:
        .. code-block:: python

            from langchain_community.utilities import SearxSearchWrapper
            # note the unsecure parameter is not needed if you pass the url scheme as
            # http
            searx = SearxSearchWrapper(searx_host="http://localhost:8888",
                                                    unsecure=True)


    _resultr   
searx_hostFunsecure)default_factoryparamsNheadersengines
categoriesquery_suffix
   k
aiosessionbefore)mode)valuesr   c                 C   s   | di }t }i |||d< | d}|rBd||d d< | d}|rbd||d d< t|dd}|dstd| d	 d
| }n|drd|d< ||d< |S )z?Validate that custom searx params are merged with default ones.r3   r5   ,r6   r0   Z
SEARX_HOSThttpzRWarning: missing the url scheme on host                 ! assuming secure https:// zhttps://zhttp://Tr1   )r$   r   joinr   
startswithprint)clsr=   Zuser_paramsdefaultr5   r6   r0   r   r   r   validate_params   s*    




z"SearxSearchWrapper.validate_paramsZforbid)extra)r3   r   c                 C   s@   t j| j| j|| j d}|js,td|jt|j}|| _	|S )zActual request to searx API.r4   r3   verifySearx API returned an error: )
requestsr$   r0   r4   r1   ok
ValueErrortextr   r/   )r   r3   Z
raw_resultresr   r   r   _searx_api_query   s    
z#SearxSearchWrapper._searx_api_queryc              
      sT  | j st 4 I d H }| j|d}| jr2d|d< |j| jfi |4 I d H @}|jsbtd|j	t
|	 I d H }|| _W d   I d H  q1 I d H s0    Y  W d   I d H  q1 I d H s0    Y  n| j j| j| j|| j d4 I d H D}|js
td|j	t
|	 I d H }|| _W d   I d H  qP1 I d H sF0    Y  |S )N)r4   r3   FsslrJ   rH   )r:   aiohttpZClientSessionr4   r1   r$   r0   rL   rM   rN   r   r/   )r   r3   sessionkwargsresponseresultr   r   r   _asearx_api_query	  s0    \4z$SearxSearchWrapper._asearx_api_query)queryr5   r6   r7   rT   r   c           
      K   s  d|i}i | j ||}| jrDt| jdkrD|d  d| j 7  < t|trnt|dkrn|d  d| 7  < t|trt|dkrd||d< t|trt|dkrd||d< | |}t|jdkr|jd }	n6t|j	dkrddd	 |j	d
| j
 D }	nd}	|	S )ao  Run query through Searx API and parse results.

        You can pass any other params to the searx query API.

        Args:
            query: The query to search for.
            query_suffix: Extra suffix appended to the query.
            engines: List of engines to use for the query.
            categories: List of categories to use for the query.
            **kwargs: extra parameters to pass to the searx API.

        Returns:
            str: The result of the query.

        Raises:
            ValueError: If an error occurred with the query.


        Example:
            This will make a query to the qwant engine:

            .. code-block:: python

                from langchain_community.utilities import SearxSearchWrapper
                searx = SearxSearchWrapper(searx_host="http://my.searx.host")
                searx.run("what is the weather in France ?", engine="qwant")

                # the same result can be achieved using the `!` syntax of searx
                # to select the engine using `query_suffix`
                searx.run("what is the weather in France ?", query_suffix="!qwant")
        qr   r@   r>   r5   r6   

c                 S   s   g | ]}| d dqS contentr   r#   .0rr   r   r   
<listcomp>d      z*SearxSearchWrapper.run.<locals>.<listcomp>NNo good search result found)r3   r7   len
isinstancer*   listrA   rP   r%   r"   r9   )
r   rX   r5   r6   r7   rT   _paramsr3   rO   toretr   r   r   run%  s$    (
"zSearxSearchWrapper.run)rX   r5   r7   rT   r   c           	         s   d|i}i | j ||}| jrDt| jdkrD|d  d| j 7  < t|trnt|dkrn|d  d| 7  < t|trt|dkrd||d< | |I dH }t|jdkr|jd }n4t|j	dkrddd	 |j	d| j
 D }nd
}|S )z Asynchronously version of `run`.rY   r   r@   r>   r5   NrZ   c                 S   s   g | ]}| d dqS r[   r#   r]   r   r   r   r`     ra   z+SearxSearchWrapper.arun.<locals>.<listcomp>rb   )r3   r7   rc   rd   r*   re   rA   rW   r%   r"   r9   )	r   rX   r5   r7   rT   rf   r3   rO   rg   r   r   r   arunj  s     	"zSearxSearchWrapper.arun)rX   num_resultsr5   r6   r7   rT   r   c           
      K   s   d|i}i | j ||}| jrDt| jdkrD|d  d| j 7  < t|trnt|dkrn|d  d| 7  < t|trt|dkrd||d< t|trt|dkrd||d< | |jd| }	t|	dkrdd	igS d
d |	D S )a$  Run query through Searx API and returns the results with metadata.

        Args:
            query: The query to search for.
            query_suffix: Extra suffix appended to the query.
            num_results: Limit the number of results to return.
            engines: List of engines to use for the query.
            categories: List of categories to use for the query.
            **kwargs: extra parameters to pass to the searx API.

        Returns:
            Dict with the following keys:
            {
                snippet:  The description of the result.
                title:  The title of the result.
                link: The link to the result.
                engines: The engines used for the result.
                category: Searx category of the result.
            }

        rY   r   r@   r>   r5   r6   NResultNo good Search Result was foundc                 S   s4   g | ],}| d d|d |d |d |d dqS r\   r   titleurlr5   category)Zsnippetrn   linkr5   rp   r#   r^   rV   r   r   r   r`     s   
z.SearxSearchWrapper.results.<locals>.<listcomp>)	r3   r7   rc   rd   r*   re   rA   rP   r"   )
r   rX   rj   r5   r6   r7   rT   rf   r3   r"   r   r   r   r"     s"    
zSearxSearchWrapper.results)rX   rj   r5   r7   rT   r   c           	         s   d|i}i | j ||}| jrDt| jdkrD|d  d| j 7  < t|trnt|dkrn|d  d| 7  < t|trt|dkrd||d< | |I dH jd| }t|dkrddigS d	d
 |D S )zdAsynchronously query with json results.

        Uses aiohttp. See `results` for more info.
        rY   r   r@   r>   r5   Nrk   rl   c                 S   s4   g | ],}| d d|d |d |d |d dqS rm   r#   rr   r   r   r   r`     s   
z/SearxSearchWrapper.aresults.<locals>.<listcomp>)	r3   r7   rc   rd   r*   re   rA   rW   r"   )	r   rX   rj   r5   r7   rT   rf   r3   r"   r   r   r   aresults  s    
zSearxSearchWrapper.aresults)NNr   )Nr   )NNr   )Nr   )&r&   r'   r(   r)   r
   r/   r   r+   r0   r*   r1   boolr	   r   r3   dictr4   r   r5   r   r6   r7   r9   intr:   r   r   classmethodr   rF   r   Zmodel_configrP   rW   rh   ri   r"   rs   r   r   r   r   r.      sz   
   

H  
'   

=  
r.   )r)   r   typingr   r   r   r   rR   rK   Zlangchain_core.utilsr   Zpydanticr   r   r	   r
   r   ru   r   r   r.   r   r   r   r   <module>   s    	