o
    ZhU                     @   s   d Z ddlZddlmZmZmZmZmZmZm	Z	 ddl
Z
ddlZddlmZm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ZG d	d
 d
eZG dd deZG dd deZdS )z4Wrapper and Tool for the Google Maps Geocoding API.     N)AnyDictListLiteralOptionalTupleType)AsyncCallbackManagerForToolRunCallbackManagerForToolRun)BaseToolget_from_dict_or_env)	BaseModel
ConfigDictField	SecretStrmodel_validatorz1https://maps.googleapis.com/maps/api/geocode/jsonc                   @   sF  e Zd ZU dZeed< eddZeed< eddZ	eed< eddZ
eed< eddZeed< ed	dZee ed
< eddZee ed< eddZeed< eddZeed< eddZdededdfddZdededdfddZdededdfddZdededdfddZdee dee fd d!Z			"d7d#ed
ee dee d$edeeef f
d%d&Z			d8d'ee d
ee dee d(eeeef  deeef f
d)d*Z			d8d#ed
ee dee d(eeeef  def
d+d,Zd-edefd.d/Z e!d0d1e"d2edefd3d4Z#		d9d#ed
ee dee deeef fd5d6Z$dS ):GoogleGeocodingAPIWrapperz&Wrapper for Google Maps Geocoding API.google_api_keyTdefaultinclude_boundsinclude_navigationinclude_metadatainclude_address_componentsenlanguageusregion   max_retries   timeoutZforbid)extracleanedresultreturnNc           	      C   s|   | j sdS g d}|dg D ],}|dg }|d}|D ]}||v r+||d |< q|dkr:|d}||d d	< qqdS )
z%Add address components if configured.N)Zstreet_numberZrouteZlocalityZcountryZpostal_codeZaddress_componentstypesZ	long_nameaddressZadministrative_area_level_1Z
short_namestate)r   get)	selfr$   r%   Zaddress_types	componentr'   nametype_Z
state_name r/   [/var/www/html/lang_env/lib/python3.10/site-packages/langchain_google_community/geocoding.py_add_components'   s   

z)GoogleGeocodingAPIWrapper._add_componentsc                 C   sR   | di }| jr%| dr|d |d d< | dr'|d |d d< dS dS dS )z#Add geometry details if configured.geometryZviewportZboundsN)r*   r   r+   r$   r%   r2   r/   r/   r0   _add_geometry>   s   

z'GoogleGeocodingAPIWrapper._add_geometryc                 C   s>   | j r|di }|d|dg |dd|d< dS dS )zAdd metadata if configured.r2   place_idr'   location_type)r5   r'   r6   metadataN)r   r*   r3   r/   r/   r0   _add_metadataG   s   
z'GoogleGeocodingAPIWrapper._add_metadatac                 C   s6   | j r|drdd |dg D |d< dS dS dS )z$Add navigation points if configured.Znavigation_pointsc                 S   s"   g | ]}|d  | dg dqS )locationZrestricted_travel_modes)r9   Zrestrictionsr*   ).0pointr/   r/   r0   
<listcomp>T   s    
z=GoogleGeocodingAPIWrapper._add_navigation.<locals>.<listcomp>Z
navigationN)r   r*   )r+   r$   r%   r/   r/   r0   _add_navigationQ   s
   
z)GoogleGeocodingAPIWrapper._add_navigationresultsc                 C   s|   g }|D ]7}|s	qd| ddid| di  di id}| || | || | || | || || q|S )zClean and format results.fullZformatted_address r9   r2   )r(   r2   )r*   r1   r4   r8   r>   append)r+   r?   Zcleaned_resultsr%   r$   r/   r/   r0   clean_results\   s   z'GoogleGeocodingAPIWrapper.clean_results
   querymax_resultsc              
   C   s  z^|  sddg dW S dd |dD }t||kr"|d| }| j|||d}|d	d
kr@|d	d|ddg dW S d
t|dg | |dg ||pU| j|pY| jddW S  ty } zdt	|g ||pp| j|pt| jddW  Y d}~S d}~ww )a*  Process geocoding request and return comprehensive results.

        This method handles both single and batch geocoding requests, returning
        detailed location information with optional components.

        Args:
            query: Location(s) to geocode.
                Examples:
                    - "Eiffel Tower"
                    - "Times Square, Central Park"
            language: Optional language code for results (e.g., "en", "fr", "ja")
            region: Optional region bias (e.g., "us", "fr", "jp")
            max_results: Maximum number of results to return (default: 10)

        Returns:
            Dict containing:
                status: Status of the request ("OK" or error status)
                total_results: Number of locations found
                results: List of dictionaries containing location data:
                    address: {
                        full: Complete formatted address
                        street_number: Building number (if available)
                        route: Street name
                        locality: City/Town
                        state: State/Province
                        country: Country
                        postal_code: Postal/ZIP code
                    }
                    geometry: {
                        location: {lat, lng} coordinates
                        viewport: Recommended viewport
                        bounds: Geographic bounds (if available)
                    }
                    metadata: {
                        place_id: Unique Google place identifier
                        types: Categories (e.g., ["establishment", "point_of_interest"])
                        location_type:(e.g., "ROOFTOP", "GEOMETRIC_CENTER")
                    }
                    navigation: List of navigation points with:
                        location: {latitude, longitude}
                        restrictions: Travel mode restrictions
                query_info: {
                    original_query: Input query
                    language: Language used
                    region: Region bias used
                }

        Example Response:
            {
                "status": "OK",
                "total_results": 2,
                "results": [
                    {
                        "address": {
                            "full": "Street, Country..",
                            "route": "Avenue Gustave Eiffel",
                            "locality": "Paris",
                            "country": "France"
                        },
                        "geometry": {
                            "location": {"lat": 48.8584, "lng": 2.2945}
                        }
                    },
                    ...
                ],
                "query_info": {
                    "original_query": "Eiffel Tower, Big Ben",
                    "language": "en",
                    "region": "us"
                }
            }

        Raises:
            ValueError: If query is empty or invalid
            Exception: For API errors or connection issues
        ERROREmpty query providedstatusmessager?   c                 S      g | ]
}|  r|  qS r/   strip)r;   qr/   r/   r0   r=          z5GoogleGeocodingAPIWrapper.results.<locals>.<listcomp>,NrE   r   r   rJ   OKerror_messagezNo results foundr?   )Zoriginal_queryr   r   rJ   total_resultsr?   
query_info)rJ   rK   r?   rW   )
rN   splitlenraw_resultsr*   rC   r   r   	Exceptionstr)r+   rE   r   r   rF   ZqueriesrZ   er/   r/   r0   r?   u   sH   S

z!GoogleGeocodingAPIWrapper.results	locations
componentsc           
      C   s   |sddg dS g }g }|D ]F}z'| j ||||d}|ddkr'|| n|||d|dd W q tyT }	 z||dt|	d W Y d	}	~	qd	}	~	ww |rYdndt|| d
d |D |t|t|t||pt| j|px| jddS )u  Process multiple locations in a single structured request.

        Efficiently handles multiple location queries, processing them as a batch
        while maintaining individual result integrity.

        Args:
            locations: List of location strings to geocode
                Examples: ["Eiffel Tower", "Times Square", "東京スカイツリー"]
            language: Optional language code for results
            region: Optional region bias
            components: Optional filters (e.g., {"country": "US"})

        Returns:
            Dict containing:
                status: Overall batch status
                total_results: Number of successful geocoding results
                results: List of location data (same structure as single results)
                errors: List of any errors encountered:
                    query: The location query that failed
                    status: Error status code
                    message: Detailed error message
                query_info: {
                    total_queries: Total locations processed
                    successful: Number of successful queries
                    failed: Number of failed queries
                    language: Language used
                    region: Region bias used
                }

        Example:
            batch_geocode(
                locations=["Eiffel Tower", "Big Ben"],
                language="en",
                components={"country": "FR"}
            )
        rG   zNo locations providedrI   )rE   r   r   r_   rJ   rS   rT   )rE   rJ   rK   Nc                 S   s&   g | ]}| d r| d g d qS )r?   r   r:   )r;   rr/   r/   r0   r=   F  s   & z;GoogleGeocodingAPIWrapper.batch_geocode.<locals>.<listcomp>)total_queries
successfulfailedr   r   )rJ   rV   r?   errorsrW   )	rZ   r*   rB   r[   r\   rY   rC   r   r   )
r+   r^   r   r   r_   r?   rd   r9   r%   r]   r/   r/   r0   batch_geocode   sR   +"
z'GoogleGeocodingAPIWrapper.batch_geocodec           
      C   s  z|  sddg dW S |  | j |p| j|p| jd}|r.ddd | D |d< t| jD ]k}z:t	j
t|| jd	}|  | }|
d
dkrT|W   W S || jd krn|
d
| |
d
g dW   W S W q3 t	jjy }	 z!|| jd krddt|	 g dW  Y d}	~	  W S W Y d}	~	q3d}	~	ww W n ty }	 zddt|	 g dW  Y d}	~	S d}	~	ww ddg dS )z-Get raw results with improved error handling.rG   rH   rJ   rT   r?   r(   keyr   r   |c                 s   s"    | ]\}}| d | V  qdS ):Nr/   )r;   kvr/   r/   r0   	<genexpr>m  s    
z8GoogleGeocodingAPIWrapper.raw_results.<locals>.<genexpr>r_   paramsr"   rJ   rS      ZREQUEST_ERRORzRequest failed: NzProcessing error: zAll retry attempts failed)rN   r   get_secret_valuer   r   joinitemsranger    requestsr*   GOOGLE_MAPS_API_URLr"   raise_for_statusjson_get_error_message
exceptionsRequestExceptionr\   r[   )
r+   rE   r   r   r_   ro   attemptresponsedatar]   r/   r/   r0   rZ   R  sj   
	z%GoogleGeocodingAPIWrapper.raw_resultsrJ   c                 C   s&   dddddddd}| |d	| S )
z0Get detailed error message based on status code.zNo results found for this queryzAPI key quota exceededzQuery limit exceededz!Request was denied, check API keyzInvalid request parameterszToo many locations in requestzServer error, please try again)ZZERO_RESULTSZOVER_DAILY_LIMITZOVER_QUERY_LIMITZREQUEST_DENIEDZINVALID_REQUESTZMAX_ELEMENTS_EXCEEDEDUNKNOWN_ERRORzAPI Error: r:   )r+   rJ   Zerror_messagesr/   r/   r0   ry     s   	z,GoogleGeocodingAPIWrapper._get_error_messagebefore)modevaluesc                 C   s   t |dd}||d< |S )z,Validate that api key exists in environment.r   GOOGLE_MAPS_API_KEYr   )clsr   r   r/   r/   r0   validate_environment  s
   z.GoogleGeocodingAPIWrapper.validate_environmentc           
   
      s  z|  | j |p| jpd|p| jpdd}tj| jd}t 4 I dH r}|j	t
||d4 I dH N}| I dH }|	ddkr_| |||W  d  I dH  W  d  I dH  W S |	dd|	d	d
g dW  d  I dH  W  d  I dH  W S 1 I dH sw   Y  W d  I dH  W dS 1 I dH sw   Y  W dS  ty }	 zddt|	 g dW  Y d}	~	S d}	~	ww )a  Run query through Google Maps Geocoding API asynchronously.

        Args:
            query: The location(s) to geocode
            language: Optional language code for results
            region: Optional region bias

        Returns:
            Dict containing:
                status: Status of the request
                results: List of geocoding results
                query_info: Metadata about the request
        rA   rg   )totalNrn   rJ   rS   rG   rT   zRequest failedrf   zAsync request failed: )rN   r   rq   r   r   aiohttpZClientTimeoutr"   ZClientSessionr*   rv   rx   r?   r[   r\   )
r+   rE   r   r   ro   timeout_objsessionr}   r~   r]   r/   r/   r0   geocode_async  sB   

2z'GoogleGeocodingAPIWrapper.geocode_async)NNrD   )NNN)NN)%__name__
__module____qualname____doc__r   __annotations__r   r   boolr   r   r   r   r   r\   r   r    intr"   r   Zmodel_configr   r1   r4   r8   r>   r   rC   r   r?   re   rZ   ry   r   classmethodr   r   r/   r/   r/   r0   r      s   
 
	


 

^
G
r   c                   @   s$   e Zd ZU dZeddZeed< dS )GoogleGeocodeInputzInput for the Geocoding tool.zLocations for query.)descriptionrE   N)r   r   r   r   r   rE   r\   r   r/   r/   r/   r0   r     s   
 r   c                   @   sB  e Zd ZU dZdZeed< dZeed< eZ	e
e ed< dZeed< ed	d
Zeed< ed	d
Zeed< ed	d
Zeed< edd
Zee ed< edd
Zee ed< edd dZeed< dZed ed< 	ddedee deeeeef  eeef f fddZ	ddedee  deeeeef  eeef f fddZ!dS ) GoogleGeocodingToola  Tool that queries the Google Maps Geocoding API for batch location lookups.

    Instantiate:
        .. code-block:: python

            from tools.geocoding_wrapper import GoogleGeocodingTool

            tool = GoogleGeocodingTool(
                max_results=5,
                include_bounds=True,
                include_navigation=True,
                include_metadata=True,
                language="en"
            )

    Invoke directly:
        .. code-block:: python

            result = tool.invoke({
                "query": "Eiffel Tower, Empire State Building"
            })

    Invoke with agent:
        .. code-block:: python

            agent.invoke({
                "input": "Find coordinates of Times Square and Central Park"
            })

    Returns:
        Tuple containing:
            - List of location data with coordinates and addresses
            - Raw response data with query information
    Zgoogle_geocoder-   zbA geocoding tool for multiple locations. Input: comma-separated locations. Returns: location data.r   args_schema   rF   Tr   r   r   r   r   r   Nr   c                   C   s   t ttdddS )Nr   rA   )r   )r   r   osgetenvr/   r/   r/   r0   <lambda>  s    zGoogleGeocodingTool.<lambda>)default_factoryapi_wrapperZcontent_and_artifactresponse_formatrE   run_managerr&   c              
   C   s&  zxdd | dD }t|| jkr|d| j }t|dkr+| jj|| j| jd}n5| jj|d | j| jd}|d	d| j	|d
g d|d	dkrPdnd|d	dkrZdnddd}|d	dkrrg d|ddifW S |d
 |fW S  t
y } zg dt|ifW  Y d}~S d}~ww )zUse the tool.c                 S   rL   r/   rM   )r;   locr/   r/   r0   r=   (  rP   z,GoogleGeocodingTool._run.<locals>.<listcomp>rQ   Nrp   )r^   r   r   r   rR   rJ   r?   rS   )ra   rb   rc   rU   errorrT   Geocoding failed)rX   rY   rF   r   re   r   r   rZ   r*   rC   r[   r\   )r+   rE   r   r^   r?   rZ   r]   r/   r/   r0   _run!  s8   

zGoogleGeocodingTool._runc              
      s   z)| j j|| j| jdI dH }|ddkr"g d|ddifW S |dg |fW S  tyD } zg dt|ifW  Y d}~S d}~ww )	zUse the tool asynchronously.rR   NrJ   rS   r   rT   r   r?   )r   r   r   r   r*   r[   r\   )r+   rE   r   r%   r]   r/   r/   r0   _arunI  s   
zGoogleGeocodingTool._arun)N)"r   r   r   r   r-   r\   r   r   r   r   r   r   rF   r   r   r   r   r   r   r   r   r   r   r   r   r   r
   r   r   r   r   r   r	   r   r/   r/   r/   r0   r     s@   
 #

+r   )r   r   typingr   r   r   r   r   r   r   r   ru   Zlangchain_core.callbacksr	   r
   Zlangchain_core.toolsr   Zlangchain_core.utilsr   Zpydanticr   r   r   r   r   rv   r   r   r   r/   r/   r/   r0   <module>   s     $   P