o
    ȳgx?                     @   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 def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   f/var/www/html/chatdoc2/venv/lib/python3.10/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< def fddZdefdd	Ze	de
fd
dZe	de
f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   	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   
   |  dS )zGSilence mypy for accessing this field.

        :meta private:
        resultsgetr    r   r   r   r#      s   
zSearxResults.resultsc                 C   r"   )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dedefddZeddZdedefddZ dedefddZ!					d(de	deee	  deee	  dee	 dede	fdd Z"			d)de	deee	  dee	 dede	f
d!d"Z#					d(de	d#edeee	  deee	  dee	 dedee fd$d%Z$			d)de	d#edeee	  dee	 dedee f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}|r!d||d d< | d}|r1d||d d< t|dd}|dsItd| d	 d
| }n	|drRd|d< ||d< |S )z?Validate that custom searx params are merged with default ones.r4   r6   ,r7   r1   
SEARX_HOSThttpzRWarning: missing the url scheme on host                 ! assuming secure https:// zhttps://zhttp://Tr2   )r%   r   joinr   
startswithprint)clsr>   user_paramsdefaultr6   r7   r1   r   r   r   validate_params   s*   




z"SearxSearchWrapper.validate_paramsforbid)extrac                 C   s@   t j| j| j|| j d}|jstd|jt|j}|| _	|S )zActual request to searx API.r5   r4   verifySearx API returned an error: )
requestsr%   r1   r5   r2   ok
ValueErrortextr   r0   )r   r4   
raw_resultresr   r   r   _searx_api_query   s   
z#SearxSearchWrapper._searx_api_queryc              
      sV  | j skt 4 I d H R}| j|d}| jrd|d< |j| jfi |4 I d H  }|js2td|j	t
|	 I d H }|| _W d   I d H  n1 I d H sNw   Y  W d   I d H  |S 1 I d H sdw   Y  |S | j j| j| j|| j d4 I d H !}|jstd|j	t
|	 I d H }|| _W d   I d H  |S 1 I d H sw   Y  |S )N)r5   r4   FsslrN   rL   )r;   aiohttpClientSessionr5   r2   r%   r1   rP   rQ   rR   r   r0   )r   r4   sessionkwargsresponseresultr   r   r   _asearx_api_query	  sB   *z$SearxSearchWrapper._asearx_api_queryqueryrZ   c           
      K   s  d|i}i | j ||}| jr"t| jdkr"|d  d| j 7  < t|tr7t|dkr7|d  d| 7  < t|trIt|dkrId||d< t|tr[t|dkr[d||d< | |}t|jdkrn|jd }	|	S t|j	dkrddd	 |j	d
| j
 D }	|	S 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   rB   r?   r6   r7   

c                 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)r4   r8   len
isinstancer+   listrC   rU   r&   r#   r:   )
r   r^   r6   r7   r8   rZ   _paramsr4   rT   toretr   r   r   run%  s(   (

 zSearxSearchWrapper.runc           	         s   d|i}i | j ||}| jr#t| jdkr#|d  d| j 7  < t|tr8t|dkr8|d  d| 7  < t|trJt|dkrJd||d< | |I dH }t|jdkr`|jd }|S t|j	dkryddd	 |j	d| j
 D }|S d
}|S )z Asynchronously version of `run`.r_   r   rB   r?   r6   Nr`   c                 S   ra   rb   r$   rd   r   r   r   rg     rh   z+SearxSearchWrapper.arun.<locals>.<listcomp>ri   )r4   r8   rj   rk   r+   rl   rC   r]   r&   r#   r:   )	r   r^   r6   r8   rZ   rm   r4   rT   rn   r   r   r   arunj  s&   	
 zSearxSearchWrapper.arunnum_resultsc           
      K   s   d|i}i | j ||}| jr"t| jdkr"|d  d| j 7  < t|tr7t|dkr7|d  d| 7  < t|trIt|dkrId||d< t|tr[t|dkr[d||d< | |jd| }	t|	dkrpd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   rB   r?   r6   r7   NResultNo good Search Result was foundc                 S   4   g | ]}| d d|d |d |d |d dqS rc   r   titleurlr6   category)snippetrv   linkr6   rx   r$   re   r\   r   r   r   rg         
z.SearxSearchWrapper.results.<locals>.<listcomp>)	r4   r8   rj   rk   r+   rl   rC   rU   r#   )
r   r^   rq   r6   r7   r8   rZ   rm   r4   r#   r   r   r   r#     s"   
zSearxSearchWrapper.resultsc           	         s   d|i}i | j ||}| jr#t| jdkr#|d  d| j 7  < t|tr8t|dkr8|d  d| 7  < t|trJt|dkrJd||d< | |I dH jd| }t|dkrbddigS d	d
 |D S )zdAsynchronously query with json results.

        Uses aiohttp. See `results` for more info.
        r_   r   rB   r?   r6   Nrr   rs   c                 S   rt   ru   r$   r{   r   r   r   rg     r|   z/SearxSearchWrapper.aresults.<locals>.<listcomp>)	r4   r8   rj   rk   r+   rl   rC   r]   r#   )	r   r^   rq   r6   r8   rZ   rm   r4   r#   r   r   r   aresults  s    
zSearxSearchWrapper.aresults)NNr   )Nr   )&r'   r(   r)   r*   r
   r0   r   r,   r1   r+   r2   boolr	   r   r4   dictr5   r   r6   r   r7   r8   r:   intr;   r   r   classmethodr   rI   r   model_configrU   r]   ro   rp   r#   r}   r   r   r   r   r/      s   
 


H

'


=
r/   )r*   r   typingr   r   r   r   rW   rO   langchain_core.utilsr   pydanticr   r   r	   r
   r   r   r   r   r/   r   r   r   r   <module>   s     	