""" AUTHOR: Khushal P Soonderji DATE: Wednesday, 27th Nov., 2024 OBJECTIVE: To define the interaction between the UI layer and the database connectivity in one place. Here we shall handle all the activities for OAuth2.0 authorization requests for all the users of our service. REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # To make sibling directories accessible for imports: import sys from langchain.chains.summarize.stuff_prompt import prompt_template sys.path.append(".") sys.path.append("..") # My async utils: from utils_v2.string import json from utils_v2.date_time import date_time from utils_v2.database.async_mysql_v2 import AsyncMySQL from utils_v2.database.async_mongo_v2 import AsyncMongo # Mail Clients: from utils_v2.goog.gmail.gmail_client import AsyncGMailClient from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens # Base model: from models.behaviour.base import BaseModel # To work with MongoDB: from bson import ObjectId # To work with LLMs: from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # To work with datatypes: from typing import Literal # To make deep-copies: import copy # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** CLASSES *** # ***** **** # ***************************************************************************************************************** class MailSyncModel(BaseModel): # For MongoDB: AUTH_COLLECTION = "_authTokens" MAIL_COLLECTION = "_messages" # For AI Magic through LLMs: prompt_template = ChatPromptTemplate.from_messages([ ( "system", "You're a mail summary expert that summarizes mails in 150 chars or less. HIDE SENSITIVE INFO (LIKE OTPS) FROM THE SUMMARY." ), ( "user", "Please summarize this mail: \"\"\"{mail}\"\"\"" ) ]) async def sync_one( self, mongo_conn: AsyncMongo, user_identifier: str | ObjectId, mail_client: AsyncGMailClient, tokens: GoogleAuthTokens, message_id: str, llm: ChatOpenAI = None, session_token: str = None, force_sync: bool = False ) -> ObjectId: # ┏┓┓ ┓ ┏┓ • • ┳┓ ┓ # ┃ ┣┓┏┓┏┃┏ ┣ ┓┏┓┏╋┓┏┓┏┓ ┣┫┏┓┏┏┓┏┓┏┫┏ # ┗┛┛┗┗ ┗┛┗ ┗┛┛┗┗┛┗┗┛┗┗┫ ┛┗┗ ┗┗┛┛ ┗┻┛ # ┛ # Check if you already have that mail in your database: existing_record = await mongo_conn.find_one( collection = self.MAIL_COLLECTION, filter = { "messageType": "email", "$or": [ {"payload.messageId": message_id} ] }, projection = {"_id": True} ) # If there already exists such a record, and we haven't been forced to re-sync it: if existing_record and not force_sync: return existing_record["_id"] # ┏┓ ┓┏ • ┓ ┓ # ┃┃┏┓┏┓┏┓┏┓┏┓┏┓ ┃┃┏┓┏┓┓┏┓┣┓┃┏┓┏ # ┣┛┛ ┗ ┣┛┗┻┛ ┗ ┗┛┗┻┛ ┗┗┻┗┛┗┗ ┛ # ┛ mail_payload = None mail_id = existing_record["_id"] if existing_record else None # ┏┓┳┳┓ •┓ # ┃┓┃┃┃┏┓┓┃ # ┗┛┛ ┗┗┻┗┗ if isinstance(mail_client, AsyncGMailClient): # Refresh the tokens: tokens_refreshed # Fetch the mail formatted message: client_response = await mail_client.get_message( tokens = tokens, message_id = message_id, return_raw = False ) # If the fetch was successful: if client_response.success: # Summarize the content: prompt = self.prompt_template.invoke({"mail": client_response.data.pop["unformattedText"]}) llm_response = await llm.ainvoke(prompt) client_response.data["aiSnippet"] = llm_response.content # Note down the response: mail_payload = client_response.data # ┏┓ ┏┳┓┓ ┳┳┓ •┓ # ┗┓┓┏┏┓┏ ┃ ┣┓┏┓ ┃┃┃┏┓┓┃ # ┗┛┗┫┛┗┗ ┻ ┛┗┗ ┛ ┗┗┻┗┗ # ┛ if mail_payload: pass # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": pass