
    7|hx?                         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Z G d d	e      Z G d
 de      Zy)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                      dddS )Nenjson)languageformat r       i/var/www/html/test/engine/venv/lib/python3.12/site-packages/langchain_community/utilities/searx_search.py_get_default_paramsr      s    //r   c                   p     e Zd ZU dZdZeed<   def fdZdefdZe	de
fd       Ze	de
fd	       Z xZS )
SearxResultsz,Dict like wrapper around search api results. _datadatac                 \    t        j                  |      }t        |   |       | | _        y)zATake a raw result from Searx and make it into a dict like object.N)r   loadssuper__init____dict__)selfr   	json_data	__class__s      r   r   zSearxResults.__init__   s%    JJt$	#r   r   c                     | j                   S )z$Text representation of searx result.)r   r!   s    r   __str__zSearxResults.__str__   s    zzr   c                 $    | j                  d      S )zGSilence mypy for accessing this field.

        :meta private:
        resultsgetr%   s    r   r(   zSearxResults.results   s     xx	""r   c                 $    | j                  d      S )z#Helper accessor on the json result.answersr)   r%   s    r   r,   zSearxResults.answers   s     xx	""r   )__name__
__module____qualname____doc__r   str__annotations__r   r&   propertyr   r(   r,   __classcell__)r#   s   @r   r   r      s]    6E3OS   # # # # # #r   r   c                   L   e Zd ZU dZ e       Zeed<   dZe	ed<   dZ
eed<    ee      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dedefd              Z ed      ZdedefdZ dedefdZ!	 	 	 d!de	deee	      deee	      dee	   dede	fdZ"	 	 d"de	deee	      dee	   dede	f
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Z$	 	 d"de	dedeee	      dee	   dedee   fd Z%y	)#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                    |j                  di       }t               }i |||d<   |j                  d      }|rdj                  |      |d   d<   |j                  d      }|rdj                  |      |d   d<   t        |dd      }|j	                  d      st        d| d	       d
|z   }n|j	                  d      rd|d<   ||d<   |S )z?Validate that custom searx params are merged with default ones.r;   r=   ,r>   r8   
SEARX_HOSThttpzRWarning: missing the url scheme on host                 ! assuming secure https:// zhttps://zhttp://Tr9   )r*   r   joinr   
startswithprint)clsrE   user_paramsdefaultr=   r>   r8   s          r   validate_paramsz"SearxSearchWrapper.validate_params   s     jj2.%'5g55x**Y'*-((7*;F8Y'ZZ-
-0XXj-AF8\*)&,M
$$V,++5,a9 $j0J""9-!%F:)|r   forbid)extrac                     t        j                  | j                  | j                  || j                         }|j
                  st        d|j                        t        |j                        }|| _	        |S )zActual request to searx API.r<   r;   verifySearx API returned an error: )
requestsr*   r8   r<   r9   ok
ValueErrortextr   r7   )r!   r;   
raw_resultress       r   _searx_api_queryz#SearxSearchWrapper._searx_api_query   s`    \\OOLL}}$	

 }}<jooNN:??+
r   c                   K   | j                   st        j                         4 d {   }| j                  |d}| j                  rd|d<    |j
                  | j                  fi |4 d {   }|j                  st        d|j                        t        |j                          d {         }|| _        d d d       d {    d d d       d {    S | j                   j                  | j                  | j                  || j                         4 d {   }|j                  st        d|j                        t        |j                          d {         }|| _        d d d       d {    |S 7 Z7 7 7 # 1 d {  7  sw Y   xY w7 # 1 d {  7  sw Y   S xY w7 7 Z7 A# 1 d {  7  sw Y   S xY ww)N)r<   r;   FsslrW   rU   )rB   aiohttpClientSessionr<   r9   r*   r8   rY   rZ   r[   r   r7   )r!   r;   sessionkwargsresponseresults         r   _asearx_api_queryz$SearxSearchWrapper._asearx_api_query	  s    ,,. * *'#||$  ==$)F5M&7;;tA&A * *X#;;()H(--XX)*?@F#)DL	* ** *0  **==(	 +  	& 	&
 {{$%DhmmTT%HMMO&;<%	& 	& 1** +@* * * ** * * *0 	& '<	& 	& 	& 	& s   %GFGAF"-F.F"1;F,F-F<F"F	F"GF AG F8!G$;F>F:
 F>/G:F<;GF"F	F"F	FF	F" G"F5(F+)F50	G:F><G>GGGGqueryrd   c           	         d|i}i | j                   ||}| j                  r2t        | j                        dkD  r|dxx   d| j                  z   z  cc<   t        |t              rt        |      dkD  r|dxx   d|z   z  cc<   t        |t
              r"t        |      dkD  rdj                  |      |d<   t        |t
              r"t        |      dkD  rdj                  |      |d<   | j                  |      }t        |j                        dkD  r|j                  d   }	|	S t        |j                        dkD  rHdj                  |j                  d| j                   D 
cg c]  }
|
j                  d	d
       c}
      }	|	S d}	|	S c c}
w )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   rJ   rG   r=   r>   

Ncontentr   No good search result found)r;   r?   len
isinstancer1   listrK   r^   r,   r(   rA   r*   )r!   rh   r=   r>   r?   rd   _paramsr;   r]   toretrs              r   runzSearxSearchWrapper.run%  sl   P 
 6DKK575f5T%6%6!7!!;3K3!2!222KlC(S->-B3K3--Kgt$W)9 # 1F9j$'C
Oa,?#&88J#7F< ##F+s{{aKKNE  !KKs{{8TVV?T U!y"!5 UVE  2E	 !Vs   Fc           	        K   d|i}i | j                   ||}| j                  r2t        | j                        dkD  r|dxx   d| j                  z   z  cc<   t        |t              rt        |      dkD  r|dxx   d|z   z  cc<   t        |t
              r"t        |      dkD  rdj                  |      |d<   | j                  |       d{   }t        |j                        dkD  r|j                  d   }|S t        |j                        dkD  rHdj                  |j                  d| j                   D 	cg c]  }	|	j                  dd	       c}	      }|S d
}|S 7 c c}	w w)z Asynchronously version of `run`.rj   r   rJ   rG   r=   Nrk   rl   r   rm   )r;   r?   rn   ro   r1   rp   rK   rg   r,   r(   rA   r*   )
r!   rh   r=   r?   rd   rq   r;   r]   rr   rs   s
             r   arunzSearxSearchWrapper.arunj  sO     
 6DKK575f5T%6%6!7!!;3K3!2!222KlC(S->-B3K3--Kgt$W)9 # 1F9**622s{{aKKNE  !KKs{{8TVV?T U!y"!5 UVE  2E 3 !Vs%   C	E$EA+E$7EE$E$num_resultsc           	         d|i}i | j                   ||}| j                  r2t        | j                        dkD  r|dxx   d| j                  z   z  cc<   t        |t              rt        |      dkD  r|dxx   d|z   z  cc<   t        |t
              r"t        |      dkD  rdj                  |      |d<   t        |t
              r"t        |      dkD  rdj                  |      |d<   | j                  |      j                  d| }	t        |	      dk(  rdd	igS |	D 
cg c]&  }
|
j                  d
d      |
d   |
d   |
d   |
d   d( c}
S c c}
w )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.
            }

        rj   r   rJ   rG   r=   r>   NResultNo good Search Result was foundrl   r   titleurlcategorysnippetr{   linkr=   r}   )
r;   r?   rn   ro   r1   rp   rK   r^   r(   r*   )r!   rh   rw   r=   r>   r?   rd   rq   r;   r(   rf   s              r   r(   zSearxSearchWrapper.results  sa   > 
 6DKK575f5T%6%6!7!!;3K3!2!222KlC(S->-B3K3--Kgt$W)9 # 1F9j$'C
Oa,?#&88J#7F< ''/77Ew<1@ABB "	
  "::i4u!),":.	
 		
 	
s   +E
c           	      V  K   d|i}i | j                   ||}| j                  r2t        | j                        dkD  r|dxx   d| j                  z   z  cc<   t        |t              rt        |      dkD  r|dxx   d|z   z  cc<   t        |t
              r"t        |      dkD  rdj                  |      |d<   | j                  |       d{   j                  d| }t        |      dk(  rddigS |D 	cg c]&  }	|	j                  d	d
      |	d   |	d   |	d   |	d   d( c}	S 7 Vc c}	w w)zdAsynchronously query with json results.

        Uses aiohttp. See `results` for more info.
        rj   r   rJ   rG   r=   Nry   rz   rl   r   r{   r|   r}   r~   )
r;   r?   rn   ro   r1   rp   rK   rg   r(   r*   )
r!   rh   rw   r=   r?   rd   rq   r;   r(   rf   s
             r   aresultszSearxSearchWrapper.aresults  sE     
 6DKK575f5T%6%6!7!!;3K3!2!222KlC(S->-B3K3--Kgt$W)9 # 1F9//77@@+Nw<1@ABB "	
  "::i4u!),":.	
 		
	 8	
s$   C	D)D"(D)4+D$D)$D))NNr   )Nr   )&r-   r.   r/   r0   r   r7   r   r2   r8   r1   r9   boolr
   r   r;   dictr<   r   r=   r   r>   r?   rA   intrB   r   r   classmethodr   rQ   r	   model_configr^   rg   rt   rv   r(   r   r   r   r   r6   r6      sn   6 (MG\)JHd)<=FD="GXd^"#%GXd3i %&(Jc#("$L(3-$AsK $J$(#T c   $6 Lt  d | > (,*.&(CC $s)$C T#Y'	C
 smC C 
CP (,&(	!! $s)$! sm	!
 ! 
!N (,*.&(7
7
 7
 $s)$	7

 T#Y'7
 sm7
 7
 
d7
z (,&($
$
 $
 $s)$	$

 sm$
 $
 
d$
r   r6   )r0   r   typingr   r   r   r   ra   rX   langchain_core.utilsr   pydanticr   r	   r
   r   r   r   r   r   r6   r   r   r   <module>r      sP   B  , ,   5 0T 0#4 #:x
 x
r   