U
    ™ÀÂhù@  ã                   @   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
mZmZmZmZ ddl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)Ú	BaseModelÚFieldÚPrivateAttrÚroot_validatorÚ	validator)Úget_from_dict_or_env©Úreturnc                   C   s
   dddœS )NÚenÚjson)ÚlanguageÚformat© r   r   r   úN/tmp/pip-unpacked-wheel-9gdii04g/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ƒeedœdd„ƒZeddeedœdd„ƒZG d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 )0Ú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)Úvr   c              
   C   sH   |rDzddl }| ¡  W n* tk
rB } zt|ƒ W 5 d}~X Y nX |S )zDisable SSL warnings.r   N)Úurllib3Údisable_warningsÚImportErrorÚprint)Úclsr;   r<   Úer   r   r   Údisable_ssl_warningsÙ   s    z'SearxSearchWrapper.disable_ssl_warningsT)Úpre)Úvaluesr   c                 C   s¶   |  di ¡}tƒ }||–|d< |  d¡}|r>d |¡|d d< |  d¡}|r^d |¡|d d< t|ddƒ}| d¡sŽtd|› d	ƒ d
| }n| d¡rªd|d< |  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   Ú
startswithr?   rB   )r@   rD   Zuser_paramsÚdefaultr5   r6   r0   r   r   r   Úvalidate_paramsç   s,    


ÿÿ


z"SearxSearchWrapper.validate_paramsc                   @   s   e Zd ZdZdS )zSearxSearchWrapper.ConfigZforbidN)r&   r'   r(   Úextrar   r   r   r   ÚConfig  s   rM   )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                 Ã   sü   | j s˜t ¡ 4 I d H št}| j|dœ}| jr2d|d< |j| jf|Ž4 I d H š0}|js^td|j	ƒ‚t
| 	¡ I d H ƒ}|| _W 5 Q I d H R X W 5 Q I d H R X n`| j j| j| j|| j d4 I d H š0}|jsÐtd|j	ƒ‚t
| 	¡ I d H ƒ}|| _W 5 Q I d H R X |S )N)r4   r3   FÚsslrP   rN   )r:   ÚaiohttpZClientSessionr4   r1   r$   r0   rR   rS   rT   r   r/   )r   r3   ÚsessionÚkwargsÚresponseÚresultr   r   r   Ú_asearx_api_query  s0    þ(üz$SearxSearchWrapper._asearx_api_query)Úqueryr5   r6   r7   rZ   r   c           
      K   s  d|i}| j ||–}| jr>t| jƒdkr>|d  d| j 7  < t|tƒrht|ƒdkrh|d  d| 7  < t|tƒrŒt|ƒdkrŒd |¡|d< t|tƒr°t|ƒdkr°d |¡|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   rG   rE   r5   r6   ú

c                 S   s   g | ]}|  d d¡‘qS ©Úcontentr   r#   ©Ú.0Úrr   r   r   Ú
<listcomp>q  s     z*SearxSearchWrapper.run.<locals>.<listcomp>NúNo good search result found)r3   r7   ÚlenÚ
isinstancer*   ÚlistrH   rV   r%   r"   r9   )
r   r^   r5   r6   r7   rZ   Ú_paramsr3   rU   Útoretr   r   r   Úrun2  s&    ( ÿ
"zSearxSearchWrapper.run)r^   r5   r7   rZ   r   c           	      Ë   sî   d|i}| j ||–}| jr>t| jƒdkr>|d  d| j 7  < t|tƒrht|ƒdkrh|d  d| 7  < t|tƒrŒt|ƒdkrŒd |¡|d< |  |¡I dH }t|jƒdkr¶|jd }n4t|j	ƒdkræd dd	„ |j	d| j
… D ƒ¡}nd
}|S )z Asynchronously version of `run`.r_   r   rG   rE   r5   Nr`   c                 S   s   g | ]}|  d d¡‘qS ra   r#   rc   r   r   r   rf   ”  s     z+SearxSearchWrapper.arun.<locals>.<listcomp>rg   )r3   r7   rh   ri   r*   rj   rH   r]   r%   r"   r9   )	r   r^   r5   r7   rZ   rk   r3   rU   rl   r   r   r   Úarunw  s"    	 ÿ"zSearxSearchWrapper.arun)r^   Únum_resultsr5   r6   r7   rZ   r   c           
      K   sè   d|i}| j ||–}| jr>t| jƒdkr>|d  d| j 7  < t|tƒrht|ƒdkrh|d  d| 7  < t|tƒrŒt|ƒdkrŒd |¡|d< t|tƒr°t|ƒdkr°d |¡|d< |  |¡jd|… }	t|	ƒdkrÚd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.
            }

        r_   r   rG   rE   r5   r6   NÚResultúNo good Search Result was foundc                 S   s4   g | ],}|  d d¡|d |d |d |d dœ‘qS ©rb   r   ÚtitleÚurlr5   Úcategory)Zsnippetrs   Úlinkr5   ru   r#   ©rd   r\   r   r   r   rf   È  s   ú
ûz.SearxSearchWrapper.results.<locals>.<listcomp>)	r3   r7   rh   ri   r*   rj   rH   rV   r"   )
r   r^   ro   r5   r6   r7   rZ   rk   r3   r"   r   r   r   r"   š  s$     ÿ
øzSearxSearchWrapper.results)r^   ro   r5   r7   rZ   r   c           	      Ë   sÊ   d|i}| j ||–}| jr>t| jƒdkr>|d  d| j 7  < t|tƒrht|ƒdkrh|d  d| 7  < t|tƒrŒt|ƒdkrŒd |¡|d< |  |¡I dH jd|… }t|ƒdkr¼ddigS d	d
„ |D ƒS )zdAsynchronously query with json results.

        Uses aiohttp. See `results` for more info.
        r_   r   rG   rE   r5   Nrp   rq   c                 S   s4   g | ],}|  d d¡|d |d |d |d dœ‘qS rr   r#   rw   r   r   r   rf   î  s   ú
ûz/SearxSearchWrapper.aresults.<locals>.<listcomp>)	r3   r7   rh   ri   r*   rj   rH   r]   r"   )	r   r^   ro   r5   r7   rZ   rk   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
   rB   r	   r   rK   rM   rV   r]   rm   rn   r"   rx   r   r   r   r   r.   ²   sx   
   û

ùH  ü
ú'   ú

ø=  û
ùr.   )r)   r   Útypingr   r   r   r   rX   rQ   Zlangchain_core.pydantic_v1r   r   r   r	   r
   Zlangchain_core.utilsr   rz   r   r   r.   r   r   r   r   Ú<module>   s    