
    Ng                        d dl 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 dlmZ d dlmZ d dlmZ erd dlZddZ G d de          ZdS )    )annotations)datetime)Path)TYPE_CHECKINGIteratorListOptionalUnion)BaseChatLoader)ChatSession)HumanMessageNnanosecondsintreturnr   c                    | dz  }t          ddd                                          }||z   }t          j        |          S )zConvert nanoseconds since 2001 to a datetime object.

    Args:
        nanoseconds (int): Nanoseconds since January 1, 2001.

    Returns:
        datetime: Datetime object.
    g    eAi     )r   	timestampfromtimestamp)r   timestamp_in_secondsreference_date_secondsactual_timestamps       e/var/www/html/ai-engine/env/lib/python3.11/site-packages/langchain_community/chat_loaders/imessage.py!nanoseconds_from_2001_to_datetimer      sQ     ', &dAq11;;== .0DD !"2333    c                  \    e Zd ZdZdddZedd
            Zedd            ZddZddZ	dS )IMessageChatLoadera  Load chat sessions from the `iMessage` chat.db SQLite file.

    It only works on macOS when you have iMessage enabled and have the chat.db file.

    The chat.db file is likely located at ~/Library/Messages/chat.db. However, your
    terminal may not have permission to access this file. To resolve this, you can
    copy the file to a different location, change the permissions of the file, or
    grant full disk access for your terminal emulator
    in System Settings > Security and Privacy > Full Disk Access.
    NpathOptional[Union[str, Path]]c                H   |t          j                    dz  dz  dz  }t          |t                     r|nt          |          | _        | j                                        st          d| j         d          	 ddl}dS # t          $ r}t          d          |d}~ww xY w)	a  
        Initialize the IMessageChatLoader.

        Args:
            path (str or Path, optional): Path to the chat.db SQLite file.
                Defaults to None, in which case the default path
                ~/Library/Messages/chat.db will be used.
        NLibraryMessageszchat.dbzFile z
 not foundr   zeThe sqlite3 module is required to load iMessage chats.
Please install it with `pip install pysqlite3`)r   home
isinstancedb_pathexistsFileNotFoundErrorsqlite3ImportError)selfr   r'   es       r   __init__zIMessageChatLoader.__init__1   s     <9;;*Z7)CD)$55Ett4::|""$$ 	F#$DDL$D$D$DEEE	NNNNN 	 	 	A  	s   <B 
B!BB!attributed_bodybytesr   strc                   |                      d          d         dd         }|d         d}}|d         dk    r%t                              |dd         d          d}}||||z                                d	d
          S )u  
        Parse the attributedBody field of the message table
        for the text content of the message.

        The attributedBody field is a binary blob that contains
        the message content after the byte string b"NSString":

                              5 bytes      1-3 bytes    `len` bytes
        ... | b"NSString" |   preamble   |   `len`   |    contents    | ...

        The 5 preamble bytes are always b"+"

        The size of `len` is either 1 byte or 3 bytes:
        - If the first byte in `len` is b"" then `len` is 3 bytes long.
          So the message length is the 2 bytes after, in little Endian.
        - Otherwise, the size of `len` is 1 byte, and the message length is
          that byte.

        Args:
            attributed_body (bytes): attributedBody field of the message table.
        Return:
            str: Text content of the message.
        s   NSStringr      Nr         littlezutf-8ignore)errors)splitr   
from_bytesdecode)r,   contentlengthstarts       r   _parse_attributed_bodyz)IMessageChatLoader._parse_attributed_bodyG   s    2 "''44Q7;
A1:NN71Q3<BBAEFuuv~-.55gh5OOOr   use_chat_handle_tableboolc                "    d}d}| r|n|}d| dS )Nz
            JOIN chat_handle_join ON
                 chat_message_join.chat_id = chat_handle_join.chat_id
            JOIN handle ON
                 handle.ROWID = chat_handle_join.handle_idzE
            JOIN handle ON message.handle_id = handle.ROWID
        a@  
            SELECT  message.date,
                    handle.id,
                    message.text,
                    message.is_from_me,
                    message.attributedBody
            FROM message
            JOIN chat_message_join ON
                 message.ROWID = chat_message_join.message_id
            z`
            WHERE chat_message_join.chat_id = ?
            ORDER BY message.date ASC;
         )r=   joins_w_chat_handlejoins_no_chat_handlejoinss       r   _get_session_queryz%IMessageChatLoader._get_session_queryf   sC    
>  (=V##BV    	r   cursor'sqlite3.Cursor'chat_idr   r   c                   g }|                      |          }|                    ||f           |                                }|D ]j\  }}}	}
}|	r|	}n|r|                     |          }n&|                    t          |||t          |          |t          |
          d                     kt          |          S )z
        Load a single chat session from the iMessage chat.db.

        Args:
            cursor: SQLite cursor object.
            chat_id (int): ID of the chat session to load.

        Returns:
            ChatSession: Loaded chat session.
        )message_timemessage_time_as_datetimesender
is_from_me)roler9   additional_kwargs)messages)	rD   executefetchallr<   appendr   r   r>   r   )r)   rE   r=   rG   resultsqueryrO   daterK   textrL   attributedBodyr9   s                r   _load_single_chat_sessionz,IMessageChatLoader._load_single_chat_session   s     ')''(=>>uwj)))??$$>F 	 	:D&$
N  55nEENN#(,4U 5 5 #)&*:&6&6' '      G,,,,r   Iterator[ChatSession]c              #    K   ddl }	  |j        | j                  }n+# |j        $ r}t	          d| j         d          |d}~ww xY w|                                }d}|                    |           |                                }d}|                    |           d |                                D             }|D ]}| 	                    |||          V  |
                                 dS )z
        Lazy load the chat sessions from the iMessage chat.db
        and yield them in the required format.

        Yields:
            ChatSession: Loaded chat session.
        r   Nz Could not open iMessage DB file a,  .
Make sure your terminal emulator has disk access to this file.
   You can either copy the DB file to an accessible location or grant full disk access for your terminal emulator.  You can grant full disk access for your terminal emulator in System Settings > Security and Privacy > Full Disk Access.zaSELECT name FROM sqlite_master
                   WHERE type='table' AND name='chat_handle_join';zSELECT chat_id
        FROM message
        JOIN chat_message_join ON message.ROWID = chat_message_join.message_id
        GROUP BY chat_id
        ORDER BY MAX(date) DESC;c                    g | ]
}|d          S )r   r@   ).0rows     r   
<listcomp>z0IMessageChatLoader.lazy_load.<locals>.<listcomp>   s    888sCF888r   )r'   connectr$   OperationalError
ValueErrorrE   rP   fetchonerQ   rX   close)	r)   r'   connr*   rE   rT   is_chat_handle_join_existschat_idsrG   s	            r   	lazy_loadzIMessageChatLoader.lazy_load   sD      	
	"7?4<00DD' 	 	 	Q4< Q Q Q  	 F 	u%+__%6%6"$
 	u88foo&7&7888 	 	G002G      	

s    
AAA)N)r   r   )r,   r-   r   r.   )r=   r>   r   r.   )rE   rF   r=   r>   rG   r   r   r   )r   rY   )
__name__
__module____qualname____doc__r+   staticmethodr<   rD   rX   rg   r@   r   r   r   r   %   s        	 	    , P P P \P<    \<*- *- *- *-X, , , , , ,r   r   )r   r   r   r   )
__future__r   r   pathlibr   typingr   r   r   r	   r
   langchain_core.chat_loadersr   langchain_core.chat_sessionsr   langchain_core.messagesr   r'   r   r   r@   r   r   <module>rs      s    " " " " " "             A A A A A A A A A A A A A A 6 6 6 6 6 6 4 4 4 4 4 4 0 0 0 0 0 0 NNN4 4 4 4,x x x x x x x x x xr   